athena-python-docx 0.19.0__tar.gz → 0.21.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.
Files changed (370) hide show
  1. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/CLAUDE.md +115 -33
  2. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/DOCX_EXEC_LAB.md +4 -4
  3. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/PKG-INFO +8 -9
  4. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/README.md +6 -7
  5. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/__init__.py +1 -1
  6. athena_python_docx-0.21.0/docx/_citations.py +74 -0
  7. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_http.py +122 -91
  8. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_image_utils.py +160 -1
  9. athena_python_docx-0.21.0/docx/_references.py +91 -0
  10. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/api.py +6 -6
  11. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/client.py +1 -8
  12. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/commands.py +35 -50
  13. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/comments.py +6 -2
  14. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/document.py +141 -59
  15. athena_python_docx-0.21.0/docx/enum/shape.py +30 -0
  16. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/style.py +17 -68
  17. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/errors.py +3 -3
  18. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/opc/coreprops.py +45 -0
  19. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/section.py +75 -33
  20. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/shape.py +23 -6
  21. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/shared.py +10 -8
  22. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/styles.py +88 -33
  23. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/table.py +88 -108
  24. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/hyperlink.py +13 -11
  25. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/paragraph.py +46 -78
  26. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/parfmt.py +25 -22
  27. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/run.py +50 -11
  28. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/pyproject.toml +6 -11
  29. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab.py +1 -1
  30. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/round_trip_smoke.py +6 -7
  31. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/smoke_test_block_not_found.py +2 -11
  32. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/validate_find_replace_asset.py +1 -1
  33. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/METHODOLOGY.md +9 -9
  34. athena_python_docx-0.21.0/tests/fidelity/README.md +50 -0
  35. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/fake_session.py +32 -33
  36. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/README.md +1 -1
  37. athena_python_docx-0.21.0/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +3 -0
  38. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/intentional_deviations.json +2 -2
  39. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/reports/GAP_ANALYSIS.md +5 -33
  40. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/reports/gap_report.json +9 -1688
  41. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/snapshots/athena_latest.json +2812 -580
  42. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_athena_extensions_registry.py +4 -2
  43. athena_python_docx-0.21.0/tests/test_citations.py +151 -0
  44. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_commands.py +4 -3
  45. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_create.py +5 -11
  46. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_create_from_template.py +167 -52
  47. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_factory_validation.py +2 -2
  48. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_docx_exec_lab.py +1 -1
  49. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_parity_misc.py +35 -6
  50. athena_python_docx-0.21.0/tests/test_python_docx_api_parity.py +357 -0
  51. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_hyperlink.py +6 -4
  52. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_parfmt.py +37 -17
  53. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_dimensions.py +36 -17
  54. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_smoke_integration.py +4 -5
  55. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/uv.lock +1 -1
  56. athena_python_docx-0.19.0/docx/_references.py +0 -82
  57. athena_python_docx-0.19.0/tests/fidelity/README.md +0 -71
  58. athena_python_docx-0.19.0/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -1
  59. athena_python_docx-0.19.0/tests/fidelity/runner.py +0 -486
  60. athena_python_docx-0.19.0/tests/test_python_docx_api_parity.py +0 -161
  61. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/.gitignore +0 -0
  62. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_athena_extension.py +0 -0
  63. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_batching.py +0 -0
  64. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_buffer.py +0 -0
  65. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_execution.py +0 -0
  66. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_http_doc.py +0 -0
  67. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_postproc.py +0 -0
  68. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_ptc.py +0 -0
  69. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_table_styles.py +0 -0
  70. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_timeouts.py +0 -0
  71. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/bookmarks.py +0 -0
  72. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/charts.py +0 -0
  73. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/__init__.py +0 -0
  74. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/section.py +0 -0
  75. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/table.py +0 -0
  76. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/text.py +0 -0
  77. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/exceptions.py +0 -0
  78. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/fields.py +0 -0
  79. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/footnotes.py +0 -0
  80. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/math.py +0 -0
  81. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/opc/__init__.py +0 -0
  82. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/oxml/__init__.py +0 -0
  83. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/revisions.py +0 -0
  84. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/sdt.py +0 -0
  85. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/session.py +0 -0
  86. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/settings.py +0 -0
  87. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/__init__.py +0 -0
  88. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/style.py +0 -0
  89. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/__init__.py +0 -0
  90. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/font.py +0 -0
  91. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/pagebreak.py +0 -0
  92. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/tabstops.py +0 -0
  93. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/toc.py +0 -0
  94. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/typing.py +0 -0
  95. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  96. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  97. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_server.py +0 -0
  98. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/dump_wire_fixtures.py +0 -0
  99. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/publish.sh +0 -0
  100. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/release.sh +0 -0
  101. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/__init__.py +0 -0
  102. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/conftest.py +0 -0
  103. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/__init__.py +0 -0
  104. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ab_probe_cases.py +0 -0
  105. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ab_probe_runner.py +0 -0
  106. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/auto_gen_cases.py +0 -0
  107. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/binary_round_trip.py +0 -0
  108. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/cases.py +0 -0
  109. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/complex_cases.py +0 -0
  110. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/coverage_report.py +0 -0
  111. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/extract.py +0 -0
  112. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/extreme_cases.py +0 -0
  113. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  114. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  115. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  116. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  117. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  118. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/local_runner.py +0 -0
  119. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/mega_cases.py +0 -0
  120. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshot.py +0 -0
  121. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  122. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  123. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  124. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  125. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  126. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  127. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  128. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  129. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  130. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  131. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  132. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  133. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  134. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  135. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  136. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  137. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  138. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  139. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  140. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  141. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  142. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  143. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  144. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  145. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  146. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  147. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  148. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  149. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  150. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  151. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  152. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  153. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  154. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  155. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  156. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  157. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  158. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  159. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  160. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  161. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  162. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  163. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  164. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  165. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  166. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  167. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  168. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  169. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  170. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  171. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  172. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  173. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  174. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  175. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  176. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  177. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  178. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  179. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  180. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  181. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  182. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  183. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  184. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  185. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  186. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  187. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  188. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  189. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  190. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  191. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  192. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  193. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  194. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  195. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  196. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  197. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  198. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  199. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  200. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  201. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  202. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  203. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  204. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  205. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  206. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  207. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  208. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  209. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  210. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  211. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  212. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  213. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  214. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  215. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  216. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  217. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  218. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  219. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  220. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  221. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  222. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  223. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  224. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  225. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  226. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  227. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  228. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  229. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  230. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  231. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  232. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  233. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  234. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  235. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  236. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  237. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  238. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  239. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  240. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  241. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  242. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  243. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  244. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  245. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  246. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  247. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  248. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  249. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  250. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  251. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  252. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  253. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  254. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  255. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  256. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  257. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  258. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  259. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  260. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  261. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  262. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  263. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  264. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  265. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  266. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  267. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ours_spec.json +0 -0
  268. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/parity_crawl.py +0 -0
  269. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/parity_diff.json +0 -0
  270. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/real_world_cases.py +0 -0
  271. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/round_trip_tests.py +0 -0
  272. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/stock_spec.json +0 -0
  273. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  274. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/README.md +0 -0
  275. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/__init__.py +0 -0
  276. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/baseline_gaps.json +0 -0
  277. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/compare.py +0 -0
  278. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/introspect.py +0 -0
  279. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/run_parity.py +0 -0
  280. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  281. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/test_parity_gap.py +0 -0
  282. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_add_section_extract_items.py +0 -0
  283. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_athena_extensions_contract.py +0 -0
  284. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_batching_perf.py +0 -0
  285. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_block_not_found_error.py +0 -0
  286. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_buffer.py +0 -0
  287. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  288. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_add_table_not_supported.py +0 -0
  289. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  290. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  291. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_format_stash.py +0 -0
  292. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  293. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_run_guard.py +0 -0
  294. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  295. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_text_replace_semantics.py +0 -0
  296. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_collapsed_range_format.py +0 -0
  297. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_command_dataclasses.py +0 -0
  298. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_comments.py +0 -0
  299. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_asset_id_property.py +0 -0
  300. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_clear.py +0 -0
  301. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_docx_exec_lab_server.py +0 -0
  302. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  303. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_execution_scope.py +0 -0
  304. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_find_replace_session_open.py +0 -0
  305. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_http_transport.py +0 -0
  306. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_hyperlink_coalescing.py +0 -0
  307. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_image_url_data_uri.py +0 -0
  308. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_insert_deferred.py +0 -0
  309. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_iter_inner_content.py +0 -0
  310. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_list_styles.py +0 -0
  311. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  312. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_merged_cells.py +0 -0
  313. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_oxml_shim.py +0 -0
  314. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_paragraph_text_len_cache.py +0 -0
  315. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_parity_round2.py +0 -0
  316. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_partial_failure_cascade.py +0 -0
  317. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_a_behavior.py +0 -0
  318. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_b_headers_footers.py +0 -0
  319. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_c_tables.py +0 -0
  320. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_positional_cell_id.py +0 -0
  321. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  322. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  323. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_ref_restore.py +0 -0
  324. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_pr19766_review_fixes.py +0 -0
  325. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_ptc.py +0 -0
  326. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_revisions.py +0 -0
  327. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  328. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_picture.py +0 -0
  329. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_run.py +0 -0
  330. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  331. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  332. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_comments_get.py +0 -0
  333. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_document_audit.py +0 -0
  334. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_document_element.py +0 -0
  335. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_enum_section.py +0 -0
  336. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_font_audit.py +0 -0
  337. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_header_footer.py +0 -0
  338. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_inline_shape.py +0 -0
  339. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  340. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_misc.py +0 -0
  341. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  342. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  343. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  344. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  345. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_add_break.py +0 -0
  346. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  347. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_style.py +0 -0
  348. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  349. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_text.py +0 -0
  350. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_underline.py +0 -0
  351. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_audit.py +0 -0
  352. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_onoff.py +0 -0
  353. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_settings.py +0 -0
  354. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_shared_audit.py +0 -0
  355. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_style.py +0 -0
  356. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_styles.py +0 -0
  357. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_audit.py +0 -0
  358. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_cell.py +0 -0
  359. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  360. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_layout.py +0 -0
  361. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_acceptance.py +0 -0
  362. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_font.py +0 -0
  363. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_setters_contract.py +0 -0
  364. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_table_set_cell_perf.py +0 -0
  365. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_table_style_id_resolution.py +0 -0
  366. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_temporarily_unavailable.py +0 -0
  367. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  368. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_wire_contract.py +0 -0
  369. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_xml_attr_guard.py +0 -0
  370. {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_zod_wire_contract.py +0 -0
@@ -67,11 +67,7 @@ These standard python-docx members don't apply to a Superdoc-backed SDK:
67
67
  ### Phase-3b upstream-blocked surface
68
68
 
69
69
  These are *shipped at the surface* but partially or fully no-op at
70
- runtime, pending SuperDoc SDK changes outside this repo. The
71
- upstream constraints have been verified against
72
- [SuperDoc's published docs](https://docs.superdoc.dev/document-api/reference/styles/apply)
73
- and the bundled TypeScript types in
74
- `node_modules/@superdoc-dev/sdk/dist/generated/client.d.ts`. See
70
+ runtime, pending DOCX Studio backend changes. See
75
71
  `docx-studio/PYTHON_DOCX_PARITY_GAPS.md` § *What unblocks the
76
72
  remaining work* for the exact wire-op shape needed to unblock each.
77
73
 
@@ -132,16 +128,15 @@ not file-backed. Each is documented in the relevant docstring.
132
128
 
133
129
  - **`Document.create(name=, base_url=, api_key=, parent_folder_id=, workspace_id=, docx=, agora_base_url=)`**
134
130
  classmethod. Stock python-docx returns a blank in-memory document
135
- for `Document(None)`; we can't fabricate a SuperDocument asset
131
+ for `Document(None)`; we can't fabricate a Word document asset
136
132
  client-side, so net-new asset creation is a separate factory that
137
133
  hits `POST {base_url}/docs/empty`. The constructor positional-arg
138
134
  shape (`Document(asset_id)`) is preserved for parity.
139
135
  - **`docx=path`** mirrors the upstream `Document(docx="template.docx")`
140
- constructor kwarg: when provided, the local `.docx` is uploaded to
141
- agora's `/api/super-docs/create-from-upload` and used as the seed
142
- for the new SuperDocument. The bytes are mirrored to S3 server-side
143
- so subsequent template-asset reuse is fast. Without `docx=`, the
144
- default Athena template is applied as today.
136
+ constructor kwarg: when provided, the SDK creates a normal Word
137
+ document asset through Agora's docx-studio bridge, then imports the
138
+ local `.docx` into that asset. Without `docx=`, the default Athena
139
+ template is applied as today.
145
140
  - **`agora_base_url=`** is a transport-detail kwarg only required when
146
141
  the SDK can't derive the agora host from `base_url` (or from
147
142
  `$ATHENA_AGORA_BASE_URL`). The default substitution rule replaces
@@ -222,22 +217,6 @@ Issue numbers reference `python-openxml/python-docx`.
222
217
  the same `Hyperlink` class the read path already exposes. Also
223
218
  available as `Run.add_hyperlink` for convenience.
224
219
 
225
- - **`Paragraph.add_citation(*, source, text=None, anchor=None,
226
- display_value=None, label=None) -> str`** + **`Document.remove_citation
227
- (*, citation_id, soft=True)`** — source-citation markers (Athena
228
- studio-linking; no python-docx analog, `issue=None`). Attaches a
229
- Word-style superscript citation marker pointing at an Athena asset
230
- (`source`, an `AssetReference`), optionally narrowed by `anchor` (a
231
- sheet range, PDF page, …). Renders in Olympus as a clickable superscript
232
- with a hover preview + Citations-panel entry — the same unified
233
- citation system as sheets / PPTX / native docs; clicking opens the
234
- source in a new tab. Routes through `CreateCitation` / `RemoveCitation`;
235
- the studio server derives the openable `citation_string` from
236
- `source_ref` + `source_anchor` via `@athenaintel/references` (single
237
- canonical serializer). `docx/_references.py` mirrors the pptx
238
- `AssetReference` + anchor re-exports off the shared `athena-references`
239
- package.
240
-
241
220
  - **`Run.add_field(kind, *, args=None, cached_result=None) -> Field`**
242
221
  + **`Document.fields: Fields`** — generic Word field insertion.
243
222
  Supports `"PAGE"`, `"NUMPAGES"`, `"DATE"`, `"TIME"`, `"AUTHOR"`,
@@ -405,6 +384,38 @@ Issue numbers reference `python-openxml/python-docx`.
405
384
  cleanup loops, which left horizontal-rule and scratch-content artifacts
406
385
  in the document during failed-run recoveries.
407
386
 
387
+ - **`Paragraph.add_citation(source, *, anchor=None, excerpt=None,
388
+ display_value=None) -> str`** + **`Paragraph.clear_citations()`** +
389
+ **`Document.add_citation(source, *, destination_anchor, anchor=None,
390
+ ...)`** + **`Document.remove_citation(citation_id)`** (0.20.0+) —
391
+ SDK-native Athena citations. This is the programmatic equivalent of
392
+ the user selecting DOCX text and choosing "Use selection as citation
393
+ destination/source" in Olympus: it writes the canonical document
394
+ citation record into the document's ``citations`` Y.Array and applies
395
+ the citation-blue highlight to the destination paragraph/range. It is
396
+ not a live link and does not overwrite destination text.
397
+
398
+ Common agent pattern after writing a supported claim:
399
+
400
+ ```python
401
+ from docx import Document
402
+ from docx._references import AssetReference, SheetRangeAnchor
403
+
404
+ doc = Document("asset_word")
405
+ p = doc.add_paragraph("The combined assessment identified 20,049 total vulnerabilities.")
406
+ citation_id = p.add_citation(
407
+ AssetReference(id="asset_spreadsheet"),
408
+ anchor=SheetRangeAnchor(sheet_id=0, range="B2:B8"),
409
+ excerpt="20,049 total vulnerabilities",
410
+ display_value="Vulnerability total",
411
+ )
412
+ doc.save()
413
+ ```
414
+
415
+ Use ``Document.add_citation(..., destination_anchor=PmNodeAnchor(...))``
416
+ only when you already have a DOCX editor anchor id. For normal writing,
417
+ cite the ``Paragraph`` proxy you just created or found.
418
+
408
419
  - **`Document.export_docx(path=None, *, include_revisions=False)
409
420
  -> bytes`** (0.11.4+) — export the document's current state as
410
421
  ``.docx`` bytes, optionally writing to ``path``. Closes the gap
@@ -413,16 +424,13 @@ Issue numbers reference `python-openxml/python-docx`.
413
424
  harnesses and CI workflows need a programmatic .docx export to
414
425
  diff against ``python-docx`` output that doesn't require a
415
426
  human-driven Olympus UI action. Routes through ``ExportDocx`` →
416
- apps/api → SuperDoc's official ``doc.save({out: <tmp>})`` (the
417
- recommended backend export path per the SuperDoc team — Document
418
- API, not the browser-side ``editor.exportDocx`` shim). apps/api
427
+ apps/api's backend export path. apps/api
419
428
  writes the session state to a temp ``.docx``, reads bytes back,
420
429
  base64-encodes for the wire, and unlinks the temp in a
421
430
  ``finally`` block. The SDK decodes and writes to ``path``.
422
431
  ``include_revisions=True`` raises ``DocxError`` pre-flight:
423
- ``@superdoc-dev/sdk@1.8.1``'s ``DocSaveParams`` has no
424
- ``includeRevisions`` field, so honoring the flag isn't possible
425
- through ``doc.save({out})``.
432
+ the current backend export path has no ``includeRevisions`` support,
433
+ so honoring the flag isn't possible yet.
426
434
 
427
435
  Template seeding: ``Document.create()`` (no ``docx=``) already
428
436
  produces an exportable asset because ``POST /docs/empty`` seeds
@@ -617,6 +625,80 @@ natively, the SDK should swap to the upstream signature in place;
617
625
  this section is the canonical reference for what each Athena
618
626
  extension wires up.
619
627
 
628
+ ### Behavioral-parity deviations (2026 deep-dive, v0.19.0)
629
+
630
+ A deep behavioral audit against python-docx 1.2.0 (the structural
631
+ parity ratchet only sees shape, not runtime behavior) fixed ~40
632
+ divergences so they now match upstream exactly — `Pt`/`RGBColor`
633
+ coercion, `Font.size` bare-int-is-EMU, `Font.underline`
634
+ SINGLE→`True`/NONE→`False`, `line_spacing` integer multipliers,
635
+ `line_spacing_rule` rule-only members, `Hyperlink.url`/`.address`,
636
+ `Table.autofit`/`_Row.cells`/`_Column.cells`, `Section`
637
+ orientation/start-type defaults + `Sections` slicing,
638
+ `Styles.get_by_id`/`get_style_id`/`default(LIST)`/`add_style`,
639
+ `Document.add_heading` (`ValueError`), `add_paragraph` strict heading
640
+ routing, `add_picture` native size + aspect ratio, `WD_BUILTIN_STYLE`
641
+ (now the 132-member int enum aliased to `WD_STYLE`),
642
+ `docx.enum.shape.WD_INLINE_SHAPE`, `InlineShape.type`/zero-dimensions,
643
+ and `CoreProperties` validation. These are not deviations — they close
644
+ gaps. The items below are the **residual intentional deviations** that
645
+ remain because matching upstream would break the asset-backed/HTTP
646
+ architecture or a SuperDoc constraint:
647
+
648
+ - **`WD_*` enum `.value` is the SuperDoc wire string, not the MS Word
649
+ integer constant.** `WD_ALIGN_PARAGRAPH.CENTER.value == "center"`
650
+ (upstream: `1`); `int(member)` / `member == 1` / `WD_*(1)` therefore
651
+ differ. The string value is load-bearing — every command serializes
652
+ `enum.value` directly onto the wire (`underline=value.value`,
653
+ `WD_COLOR_INDEX(v).value`, …), so int-valuing the enums would require
654
+ re-plumbing the entire command layer. Members are accessed by name
655
+ (`WD_ALIGN_PARAGRAPH.CENTER`), so the drift is academic for normal
656
+ use. (`WD_STYLE`/`WD_BUILTIN_STYLE` and `WD_INLINE_SHAPE_TYPE` are NOT
657
+ wire-load-bearing and DO carry the upstream int values.)
658
+
659
+ - **`RGBColor.from_string` additionally accepts a leading `#`.** Upstream
660
+ rejects `"#FF0000"`; agents routinely pass it, so a single `#` is
661
+ stripped before the (otherwise byte-identical) upstream slice parse.
662
+ A strict superset — every value upstream accepts parses identically.
663
+
664
+ - **`_Cell.vertical_alignment` setter accepts the four SuperDoc wire
665
+ tokens** (`"top"`/`"center"`/`"bottom"`/`"both"`) in addition to
666
+ `WD_ALIGN_VERTICAL` members. Upstream rejects all plain strings; this
667
+ is an ergonomic superset (typos like `"middle"` still raise
668
+ `ValueError`).
669
+
670
+ - **`Table.cell(row, col)` bounds-checks each axis independently** and
671
+ raises `IndexError` for an out-of-range row or column. Upstream
672
+ indexes a single flat row-major `_cells` list, so a column overflow
673
+ spills into the next row and `cell(-1, -1)` resolves against the flat
674
+ list (NOT the bottom-right cell). Athena's per-axis contract is the
675
+ more intuitive, stricter behavior for an HTTP-backed proxy that can't
676
+ cheaply enumerate every cell. `(0,0)` and in-range negative indices
677
+ behave identically to upstream.
678
+
679
+ - **`BaseStyle.style_id` returns the display name for built-ins** (so
680
+ `style_id == name`). The SDK is HTTP-only and can't read `styles.xml`
681
+ to recover the OOXML styleId (`"Heading 1"` → `"Heading1"`); the wire
682
+ format also uses the display name as the style id. Consequently
683
+ `get_by_id("Heading1", …)` / `"Heading1" in styles` won't resolve the
684
+ OOXML-id form (use the display name).
685
+
686
+ - **`Document.add_table(rows, cols)` requires `rows >= 1` and
687
+ `cols >= 1`.** Upstream allows a 0-row/0-col grid you later populate,
688
+ but SuperDoc's ProseMirror table node can't represent one; the SDK
689
+ raises eagerly rather than failing opaquely on the wire.
690
+
691
+ - **`Comment.comment_id` returns `str`, not `int`.** SuperDoc uses
692
+ non-numeric entity ids (`"c-42"`), so the upstream `int` contract
693
+ can't be honored. Tracked in `SUPERDOC_UPSTREAM_REQUESTS.md`.
694
+
695
+ - **`Section` dimension setters and `ParagraphFormat.line_spacing_rule
696
+ = None` warn-and-preserve on a clear** rather than raising (upstream
697
+ accepts `None` to clear, but SuperDoc's merging mutation ops have no
698
+ single-attribute clear). They emit a `Pending…ClearWarning` and leave
699
+ the value intact instead of destructively clearing the whole block.
700
+ Tracked in `SUPERDOC_UPSTREAM_REQUESTS.md`.
701
+
620
702
  ### If you need a deviation
621
703
 
622
704
  If there is a genuine technical reason why a deviation from python-docx is necessary:
@@ -1,7 +1,7 @@
1
1
  # DocX Execution Lab
2
2
 
3
3
  `scripts/docx_exec_lab.py` is a headless runner for quickly testing
4
- `athena-python-docx` snippets against Athena SuperDocument assets. It
4
+ `athena-python-docx` snippets against Athena Word document assets. It
5
5
  shortens the debug loop by running local SDK code directly against a
6
6
  chosen DOCX Studio API, capturing stdout/stderr/errors/timings, and
7
7
  optionally exporting the result to `.docx` for assertions.
@@ -85,10 +85,10 @@ uv run python scripts/docx_exec_lab.py \
85
85
  --export-docx
86
86
  ```
87
87
 
88
- ## Local UI With SuperDoc Embed
88
+ ## Local UI With DOCX Editor Embed
89
89
 
90
90
  The lab also includes a local-only HTML UI that wraps the same headless
91
- runner and iframes Olympus's existing SuperDoc embed route.
91
+ runner and iframes Olympus's existing DOCX editor embed route.
92
92
 
93
93
  ```bash
94
94
  cd docx-studio/python-sdk
@@ -107,7 +107,7 @@ Defaults:
107
107
  The UI accepts an `asset_id`, Python code, and optional assertions. The
108
108
  right pane can mint an editable embed token through staging Agora and
109
109
  iframe the returned `https://staging-app.athenaintel.com/embed/{token}`
110
- URL, so changes render in the real Olympus/SuperDoc viewer.
110
+ URL, so changes render in the real Olympus DOCX editor viewer.
111
111
 
112
112
  If the staging Agora URL differs, pass:
113
113
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-docx
3
- Version: 0.19.0
4
- Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
3
+ Version: 0.21.0
4
+ Summary: Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack
5
5
  Project-URL: Homepage, https://athenaintelligence.ai
6
6
  Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
7
7
  License-Expression: MIT
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # athena-python-docx
30
30
 
31
- Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Superdoc + Keryx collaborative document stack.
31
+ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Keryx-backed Word document stack.
32
32
 
33
33
  ## Quick start
34
34
 
@@ -36,7 +36,7 @@ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that
36
36
  from docx import Document
37
37
  from docx.shared import Inches, Pt, RGBColor
38
38
 
39
- # Open an existing SuperDoc asset by its Athena asset_id
39
+ # Open an existing Word document asset by its Athena asset_id
40
40
  with Document("asset_abc123") as doc:
41
41
  doc.add_heading("Market Analysis", level=1)
42
42
 
@@ -75,15 +75,14 @@ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
75
75
  Python snippet with this checkout of `athena-python-docx`, captures
76
76
  stdout/stderr/errors/timings, and can export the resulting `.docx` for
77
77
  text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
78
- an Olympus/SuperDoc embed preview pane. See `DOCX_EXEC_LAB.md`.
78
+ an Olympus Word document embed preview pane. See `DOCX_EXEC_LAB.md`.
79
79
 
80
80
  ## Environment variables
81
81
 
82
- Required when connecting to Keryx (set by Athena backend when executing in Daytona):
82
+ Required when connecting to DOCX Studio (set by Athena backend when executing in Daytona):
83
83
 
84
- - `SUPERDOC_COLLAB_TOKEN` — short-lived Keryx JWT
85
- - `KERYX_WS_URL` — Keryx WebSocket base URL
86
- - `ATHENA_WORKSPACE_ID` — workspace routing segment
84
+ - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
85
+ - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
87
86
 
88
87
  ## License
89
88
 
@@ -1,6 +1,6 @@
1
1
  # athena-python-docx
2
2
 
3
- Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Superdoc + Keryx collaborative document stack.
3
+ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Keryx-backed Word document stack.
4
4
 
5
5
  ## Quick start
6
6
 
@@ -8,7 +8,7 @@ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that
8
8
  from docx import Document
9
9
  from docx.shared import Inches, Pt, RGBColor
10
10
 
11
- # Open an existing SuperDoc asset by its Athena asset_id
11
+ # Open an existing Word document asset by its Athena asset_id
12
12
  with Document("asset_abc123") as doc:
13
13
  doc.add_heading("Market Analysis", level=1)
14
14
 
@@ -47,15 +47,14 @@ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
47
47
  Python snippet with this checkout of `athena-python-docx`, captures
48
48
  stdout/stderr/errors/timings, and can export the resulting `.docx` for
49
49
  text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
50
- an Olympus/SuperDoc embed preview pane. See `DOCX_EXEC_LAB.md`.
50
+ an Olympus Word document embed preview pane. See `DOCX_EXEC_LAB.md`.
51
51
 
52
52
  ## Environment variables
53
53
 
54
- Required when connecting to Keryx (set by Athena backend when executing in Daytona):
54
+ Required when connecting to DOCX Studio (set by Athena backend when executing in Daytona):
55
55
 
56
- - `SUPERDOC_COLLAB_TOKEN` — short-lived Keryx JWT
57
- - `KERYX_WS_URL` — Keryx WebSocket base URL
58
- - `ATHENA_WORKSPACE_ID` — workspace routing segment
56
+ - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
57
+ - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
59
58
 
60
59
  ## License
61
60
 
@@ -6,7 +6,7 @@ See CLAUDE.md for the API parity contract.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- __version__ = "0.19.0"
9
+ __version__ = "0.21.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import flush_all
@@ -0,0 +1,74 @@
1
+ """Helpers for SDK-native Athena citations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from typing import Any
7
+
8
+ from docx._references import AssetReference
9
+ from docx.commands import AddCitation
10
+
11
+
12
+ def new_citation_id() -> str:
13
+ return f"citation_{uuid.uuid4().hex[:12]}"
14
+
15
+
16
+ def source_ref_to_dict(source: AssetReference) -> dict[str, Any]:
17
+ if not isinstance(source, AssetReference):
18
+ raise TypeError(f"source must be an AssetReference; got {type(source).__name__}")
19
+ return source.to_dict()
20
+
21
+
22
+ def anchor_to_dict(anchor: object | None) -> dict[str, Any] | None:
23
+ if anchor is None:
24
+ return None
25
+ if not hasattr(anchor, "to_dict"):
26
+ raise TypeError(
27
+ "anchor must be an Anchor dataclass (SheetRangeAnchor, "
28
+ f"PmNodeAnchor, etc.) — got {type(anchor).__name__}"
29
+ )
30
+ value = anchor.to_dict()
31
+ if not isinstance(value, dict) or not value.get("type"):
32
+ raise TypeError("anchor.to_dict() must return a dict with a 'type' field")
33
+ return value
34
+
35
+
36
+ def destination_anchor_to_dict(destination_anchor: object) -> dict[str, Any]:
37
+ if hasattr(destination_anchor, "to_dict"):
38
+ destination_anchor = destination_anchor.to_dict()
39
+ if not isinstance(destination_anchor, dict):
40
+ raise TypeError(
41
+ "destination_anchor must be a PmNodeAnchor, PmNodeRangeAnchor, or wire dict"
42
+ )
43
+ anchor_type = destination_anchor.get("type")
44
+ if anchor_type == "pm_node" and destination_anchor.get("nodeId"):
45
+ return dict(destination_anchor)
46
+ if (
47
+ anchor_type == "pm_node_range"
48
+ and destination_anchor.get("startNodeId")
49
+ and destination_anchor.get("endNodeId")
50
+ ):
51
+ return dict(destination_anchor)
52
+ raise ValueError(
53
+ "destination_anchor must be {'type':'pm_node','nodeId':...} or "
54
+ "{'type':'pm_node_range','startNodeId':...,'endNodeId':...}"
55
+ )
56
+
57
+
58
+ def build_add_citation_command(
59
+ *,
60
+ destination_anchor: object,
61
+ source: AssetReference,
62
+ anchor: object | None,
63
+ excerpt: str | None,
64
+ display_value: str | None,
65
+ ) -> tuple[str, AddCitation]:
66
+ citation_id = new_citation_id()
67
+ return citation_id, AddCitation(
68
+ destination_anchor=destination_anchor_to_dict(destination_anchor),
69
+ source_ref=source_ref_to_dict(source),
70
+ source_anchor=anchor_to_dict(anchor),
71
+ citation_id=citation_id,
72
+ excerpt=excerpt,
73
+ display_value=display_value,
74
+ )