athena-python-docx 0.29.0__tar.gz → 0.30.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 (442) hide show
  1. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/AGENTS.md +44 -11
  2. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_http_doc.py +12 -4
  5. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_postproc.py +25 -0
  6. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_tracked.py +11 -0
  7. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/commands.py +20 -2
  8. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/comments.py +4 -2
  9. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/document.py +2 -1
  10. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/paragraph.py +78 -3
  11. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/pyproject.toml +1 -1
  12. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/baseline.json +2 -6
  13. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extensions_registry.py +1 -0
  14. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_http_transport.py +1 -1
  15. athena_python_docx-0.30.0/tests/test_paragraph_delete.py +186 -0
  16. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_ref_restore.py +48 -0
  17. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_tracked_revisions_offsets.py +28 -15
  18. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_wire_contract.py +1 -0
  19. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/uv.lock +1 -1
  20. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/.gitignore +0 -0
  21. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/CLAUDE.md +0 -0
  22. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/DOCX_EXEC_LAB.md +0 -0
  23. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/README.md +0 -0
  24. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_athena_extension.py +0 -0
  25. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_batching.py +0 -0
  26. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_buffer.py +0 -0
  27. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_capabilities.py +0 -0
  28. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_citations.py +0 -0
  29. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_execution.py +0 -0
  30. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_http.py +0 -0
  31. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_image_utils.py +0 -0
  32. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_ptc.py +0 -0
  33. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_references.py +0 -0
  34. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_run_order.py +0 -0
  35. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_table_styles.py +0 -0
  36. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_timeouts.py +0 -0
  37. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/api.py +0 -0
  38. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/blkcntnr.py +0 -0
  39. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/bookmarks.py +0 -0
  40. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/charts.py +0 -0
  41. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/client.py +0 -0
  42. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/drawing/__init__.py +0 -0
  43. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/__init__.py +0 -0
  44. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/base.py +0 -0
  45. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/dml.py +0 -0
  46. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/section.py +0 -0
  47. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/shape.py +0 -0
  48. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/style.py +0 -0
  49. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/table.py +0 -0
  50. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/text.py +0 -0
  51. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/errors.py +0 -0
  52. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/exceptions.py +0 -0
  53. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/fields.py +0 -0
  54. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/footnotes.py +0 -0
  55. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/__init__.py +0 -0
  56. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/exceptions.py +0 -0
  57. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/image.py +0 -0
  58. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/math.py +0 -0
  59. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/opc/__init__.py +0 -0
  60. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/opc/coreprops.py +0 -0
  61. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/oxml/__init__.py +0 -0
  62. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/revisions.py +0 -0
  63. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/sdt.py +0 -0
  64. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/section.py +0 -0
  65. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/session.py +0 -0
  66. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/settings.py +0 -0
  67. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/shape.py +0 -0
  68. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/shared.py +0 -0
  69. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/__init__.py +0 -0
  70. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/_table.py +0 -0
  71. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/latent.py +0 -0
  72. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/style.py +0 -0
  73. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/styles.py +0 -0
  74. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/table.py +0 -0
  75. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/__init__.py +0 -0
  76. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/font.py +0 -0
  77. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/hyperlink.py +0 -0
  78. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/pagebreak.py +0 -0
  79. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/parfmt.py +0 -0
  80. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/run.py +0 -0
  81. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/tabstops.py +0 -0
  82. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/toc.py +0 -0
  83. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/typing.py +0 -0
  84. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab.py +0 -0
  85. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  86. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  87. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_server.py +0 -0
  88. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/dump_wire_fixtures.py +0 -0
  89. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/release.sh +0 -0
  90. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/round_trip_smoke.py +0 -0
  91. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/smoke_test_block_not_found.py +0 -0
  92. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/validate_find_replace_asset.py +0 -0
  93. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/__init__.py +0 -0
  94. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/conftest.py +0 -0
  95. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/METHODOLOGY.md +0 -0
  96. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/README.md +0 -0
  97. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/__init__.py +0 -0
  98. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ab_probe_cases.py +0 -0
  99. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ab_probe_runner.py +0 -0
  100. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/auto_gen_cases.py +0 -0
  101. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/binary_round_trip.py +0 -0
  102. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/cases.py +0 -0
  103. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/complex_cases.py +0 -0
  104. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/coverage_report.py +0 -0
  105. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/extract.py +0 -0
  106. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/extreme_cases.py +0 -0
  107. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/fake_session.py +0 -0
  108. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/README.md +0 -0
  109. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  110. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  111. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  112. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  113. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  114. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/local_runner.py +0 -0
  115. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/mega_cases.py +0 -0
  116. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshot.py +0 -0
  117. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  118. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  119. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  120. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  121. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  122. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  123. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  124. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  125. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  126. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  127. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  128. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  129. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  130. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  131. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  132. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  133. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  134. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  135. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  136. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  137. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  138. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  139. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  140. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  141. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  142. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  143. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  144. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  145. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  146. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  147. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  148. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  149. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  150. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  151. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  152. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  153. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  154. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  155. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  156. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  157. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  158. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  159. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  160. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  161. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  162. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  163. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  164. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  165. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  166. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  167. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  168. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  169. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  170. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  171. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  172. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  173. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  174. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  175. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  176. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  177. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  178. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  179. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  180. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  181. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  182. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  183. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  184. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  185. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  186. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  187. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  188. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  189. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  190. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  191. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  192. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  193. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  194. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  195. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  196. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  197. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  198. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  199. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  200. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  201. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  202. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  203. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  204. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  205. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  206. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  207. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  208. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  209. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  210. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  211. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  212. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  213. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  214. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  215. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  216. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  217. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  218. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  219. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  220. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  221. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  222. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  223. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  224. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  225. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  226. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  227. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  228. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  229. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  230. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  231. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  232. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  233. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  234. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  235. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  236. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  237. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  238. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  239. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  240. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  241. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  242. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  243. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  244. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  245. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  246. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  247. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  248. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  249. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  250. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  251. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  252. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  253. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  254. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  255. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  256. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  257. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  258. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  259. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  260. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  261. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  262. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  263. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  264. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  265. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  266. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ours_spec.json +0 -0
  267. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/parity_crawl.py +0 -0
  268. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/parity_diff.json +0 -0
  269. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/real_world_cases.py +0 -0
  270. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/round_trip_tests.py +0 -0
  271. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/stock_spec.json +0 -0
  272. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  273. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/field_reads.json +0 -0
  274. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/note_reference_reads.json +0 -0
  275. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/ruby_reads.json +0 -0
  276. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/symbol_reads.json +0 -0
  277. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/__init__.py +0 -0
  278. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/reader.py +0 -0
  279. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/runner.py +0 -0
  280. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/sdk_driver.py +0 -0
  281. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/stock_driver.py +0 -0
  282. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/test_live_runner.py +0 -0
  283. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/README.md +0 -0
  284. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/__init__.py +0 -0
  285. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/baseline_gaps.json +0 -0
  286. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/compare.py +0 -0
  287. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/intentional_deviations.json +0 -0
  288. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/introspect.py +0 -0
  289. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  290. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/reports/gap_report.json +0 -0
  291. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/run_parity.py +0 -0
  292. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/snapshots/athena_latest.json +0 -0
  293. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  294. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/test_parity_gap.py +0 -0
  295. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_add_section.py +0 -0
  296. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_add_section_extract_items.py +0 -0
  297. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  298. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extensions_contract.py +0 -0
  299. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_batch_chunking.py +0 -0
  300. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_batching_perf.py +0 -0
  301. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_block_not_found_error.py +0 -0
  302. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_buffer.py +0 -0
  303. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  304. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_add_table_not_supported.py +0 -0
  305. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_borders_spec.py +0 -0
  306. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_fastpath_runs.py +0 -0
  307. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  308. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  309. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_format_stash.py +0 -0
  310. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  311. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_run_guard.py +0 -0
  312. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_merge.py +0 -0
  313. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_paragraphs_listed.py +0 -0
  314. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  315. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_text_replace_semantics.py +0 -0
  316. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_citations.py +0 -0
  317. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_collapsed_range_format.py +0 -0
  318. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_color_format_theme.py +0 -0
  319. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_command_dataclasses.py +0 -0
  320. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_commands.py +0 -0
  321. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_comment_paragraphs.py +0 -0
  322. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_comments.py +0 -0
  323. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_content_control_value.py +0 -0
  324. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_core_properties.py +0 -0
  325. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_asset_id_property.py +0 -0
  326. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_clear.py +0 -0
  327. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_create.py +0 -0
  328. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_create_from_template.py +0 -0
  329. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_factory_validation.py +0 -0
  330. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_docx_exec_lab.py +0 -0
  331. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_docx_exec_lab_server.py +0 -0
  332. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_drawing_image.py +0 -0
  333. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  334. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_empty_hyperlinks.py +0 -0
  335. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_enum_parity.py +0 -0
  336. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_execution_scope.py +0 -0
  337. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_export_docx_clean.py +0 -0
  338. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  339. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_refresh.py +0 -0
  340. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_runs.py +0 -0
  341. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_find_replace_session_open.py +0 -0
  342. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_hyperlink_coalescing.py +0 -0
  343. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_image_url_data_uri.py +0 -0
  344. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_page_break.py +0 -0
  345. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_alt_text.py +0 -0
  346. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_size.py +0 -0
  347. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_type.py +0 -0
  348. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shapes_floating.py +0 -0
  349. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_insert_deferred.py +0 -0
  350. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_iter_inner_content.py +0 -0
  351. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_list_styles.py +0 -0
  352. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  353. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_merged_cells.py +0 -0
  354. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_missing_modules.py +0 -0
  355. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  356. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_oxml_shim.py +0 -0
  357. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_page_break.py +0 -0
  358. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  359. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_paragraph_text_len_cache.py +0 -0
  360. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_parity_misc.py +0 -0
  361. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_parity_round2.py +0 -0
  362. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_partial_failure_cascade.py +0 -0
  363. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  364. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_a_behavior.py +0 -0
  365. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_b_headers_footers.py +0 -0
  366. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_c_tables.py +0 -0
  367. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_positional_cell_id.py +0 -0
  368. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  369. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  370. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_pr19766_review_fixes.py +0 -0
  371. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_ptc.py +0 -0
  372. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_python_docx_api_parity.py +0 -0
  373. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_read_run_ranges.py +0 -0
  374. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_repeated_node_read.py +0 -0
  375. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_restart_numbering.py +0 -0
  376. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_revisions.py +0 -0
  377. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_round_trip_smoke_script.py +0 -0
  378. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  379. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_add_picture_anchor.py +0 -0
  380. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_edges.py +0 -0
  381. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_formatting_wire.py +0 -0
  382. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_identity.py +0 -0
  383. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_mark_inheritance.py +0 -0
  384. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_table_style_objects.py +0 -0
  385. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_text_python_docx.py +0 -0
  386. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  387. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_sdk_reads_served.py +0 -0
  388. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_section_read_lengths.py +0 -0
  389. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  390. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_picture.py +0 -0
  391. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_run.py +0 -0
  392. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  393. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  394. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_comments_get.py +0 -0
  395. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_document_audit.py +0 -0
  396. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_document_element.py +0 -0
  397. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_enum_section.py +0 -0
  398. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_font_audit.py +0 -0
  399. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_header_footer.py +0 -0
  400. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_hyperlink.py +0 -0
  401. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_inline_shape.py +0 -0
  402. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  403. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_misc.py +0 -0
  404. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  405. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  406. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  407. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_parfmt.py +0 -0
  408. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  409. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_add_break.py +0 -0
  410. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  411. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_style.py +0 -0
  412. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  413. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_text.py +0 -0
  414. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_underline.py +0 -0
  415. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_audit.py +0 -0
  416. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  417. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_onoff.py +0 -0
  418. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_settings.py +0 -0
  419. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_shared_audit.py +0 -0
  420. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_style.py +0 -0
  421. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_styles.py +0 -0
  422. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_audit.py +0 -0
  423. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_cell.py +0 -0
  424. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  425. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_layout.py +0 -0
  426. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_smoke_integration.py +0 -0
  427. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_acceptance.py +0 -0
  428. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_font.py +0 -0
  429. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_formatting_writes.py +0 -0
  430. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_metadata_writes.py +0 -0
  431. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_names.py +0 -0
  432. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_setters_contract.py +0 -0
  433. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  434. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_read_reuse.py +0 -0
  435. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_set_cell_perf.py +0 -0
  436. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_style_id_resolution.py +0 -0
  437. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_temporarily_unavailable.py +0 -0
  438. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_text_control_characters.py +0 -0
  439. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_uv_lock_version.py +0 -0
  440. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  441. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_xml_attr_guard.py +0 -0
  442. {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_zod_wire_contract.py +0 -0
@@ -204,14 +204,21 @@ not file-backed. Each is documented in the relevant docstring.
204
204
  are sent with `changeMode: "tracked"`, and docx-studio records their text
205
205
  edits as Word revisions (`w:ins` / `w:del`): run and paragraph text,
206
206
  `find_replace` in the body, new paragraphs and headings (an inserted
207
- paragraph mark), tabs and line breaks, run formatting (`w:rPrChange`) and
207
+ paragraph mark), whole paragraphs deleted (`paragraph.delete()`, 0.30.0+:
208
+ its content, fields included, and its paragraph mark), tabs and line breaks,
209
+ run formatting (`w:rPrChange`) and
208
210
  `paragraph_format` properties (`w:pPrChange`). The replaced text stays, deleted,
209
211
  and the new text follows it, so the SDK keeps its paragraph lengths and
210
212
  run ranges that way (`docx/_tracked.py`): a tracked `run.text = value`
211
213
  leaves the run over `value`, after its deleted text, and the paragraph
212
- grows by `len(value)`. Every batch says so to docx-studio
213
- (`client.capabilities: ["trackedAuthoring"]`); a docx-studio refuses a
214
- tracked edit from an SDK that does not. A batch holding an edit it cannot
214
+ grows by `len(value)`. `find_replace` and (0.30.0+) `paragraph.text = value`
215
+ mark only the words that change, the words the old and new text share at
216
+ their start and end left as they are, so after a tracked `paragraph.text`
217
+ the SDK reads the paragraph's length back. Every batch says so to docx-studio
218
+ (`client.capabilities: ["trackedAuthoring", "trackedMinimalParagraphText"]`);
219
+ a docx-studio refuses a tracked edit from an SDK that does not declare
220
+ `trackedAuthoring`, and replaces a paragraph's whole text for one that
221
+ does not declare `trackedMinimalParagraphText`. A batch holding an edit it cannot
215
222
  record yet (paragraph styles, tables, pictures, lists, sections, notes,
216
223
  page breaks, header/footer/comment text) is refused (HTTP 422,
217
224
  `TrackedChangesUnsupported`) and applies nothing; reads, exports,
@@ -233,9 +240,11 @@ not file-backed. Each is documented in the relevant docstring.
233
240
 
234
241
  - **`Document.user_name: str | None` / `Document.user_email: str |
235
242
  None`** — the name sent with each batch, which DOCX Studio uses as the
236
- author of a comment that names none. It is not a tracked change's author:
237
- DOCX Studio stamps those with the signed-in user agora's access check
238
- names, so a script cannot choose who a redline's changes are by.
243
+ author of a comment that names none (unset, such a comment is by the
244
+ signed-in user, as "Jane Doe (Athena)"). It is not a tracked change's
245
+ author: DOCX Studio stamps those with the signed-in user agora's access
246
+ check names, as an agent writes for them ("Jane Doe (Athena)"), so a
247
+ script cannot choose who a redline's changes are by.
239
248
  Separate from `Document.core_properties.last_modified_by`, the
240
249
  `docProps/core.xml` metadata the SDK reads and writes as python-docx
241
250
  does.
@@ -451,6 +460,26 @@ Issue numbers reference `python-openxml/python-docx`.
451
460
  numbering reads. python-docx issue #471 (13 👍) demands access to
452
461
  list metadata. Routes through `NumberingGet`.
453
462
 
463
+ - **`Paragraph.delete()`** (0.30.0+) — delete the paragraph, its
464
+ paragraph mark included. python-docx has no paragraph delete (issue #33);
465
+ code written for it removes the element
466
+ (`p._element.getparent().remove(p._element)`), which this SDK cannot reach.
467
+ Routes through `DeleteParagraph`, sent in a request of its own after the
468
+ buffered edits (response-bearing, so a refusal raises at the call). With
469
+ tracking off docx-studio removes the paragraph, with the page and column
470
+ breaks the import keeps beside it; with `track_revisions` on it records
471
+ Word's tracked deletion of a whole paragraph: its content in `w:del`
472
+ (cross-reference and other fields with their codes and results, links,
473
+ note references) and its paragraph mark deleted, one revision. Accept All
474
+ removes it and the numbered paragraphs after it number on; Reject All
475
+ restores it. `paragraph.text = ""` leaves an empty, still numbered,
476
+ paragraph instead. docx-studio refuses (`DocxError`, nothing applied) the
477
+ document's last paragraph, one that ends a section, the only paragraph of
478
+ a table cell or content control, one holding part of a field that spans
479
+ paragraphs, one in a header, footer, comment or text box, and, tracked,
480
+ one in a table cell or holding a page break, a content control, a shape or
481
+ an equation (`DOCX_STUDIO_LIMITATIONS.md` § 32).
482
+
454
483
  - **`Paragraph.restart_numbering(start=1)`** (0.26.0+) — restart the
455
484
  paragraph's numbered list at `start`, as Word's "Restart at 1" does
456
485
  ("Set Numbering Value" for another start). All `"List Number"`
@@ -648,8 +677,11 @@ Issue numbers reference `python-openxml/python-docx`.
648
677
  leaves out the author, last-modified-by, revision, company, manager,
649
678
  template, editing-time and hyperlink-base properties, rsids, document
650
679
  variables, custom properties, Custom XML (a content control bound to it
651
- keeps its content, not its binding), the attached template and the
652
- thumbnail; ``clear_title=True`` drops the title too. The live document is
680
+ keeps its content, not its binding), the attached template, the attached
681
+ XML schema and the thumbnail; ``clear_title=True`` drops the title too.
682
+ Bookmarks, the creation date and the sensitivity label stay (the route's
683
+ ``removeSensitivityLabel=1`` drops the label; the SDK does not send it).
684
+ The live document is
653
685
  not changed. The SDK refuses (``DocxUnsupportedCommandError``) an answer
654
686
  without ``X-Docx-Clean-Copy: 1``, the plain export an older docx-studio
655
687
  sends, and raises ``DocxError`` with docx-studio's reason when a header,
@@ -990,8 +1022,9 @@ architecture or a DOCX Studio constraint:
990
1022
  `""`.** `Document.add_comment` / `Comments.add_comment` send `author`
991
1023
  and `initials` and docx-studio stores them as `w:author` /
992
1024
  `w:initials`, as python-docx does; with none (python-docx's default
993
- `""`) the author is `Document.user_name`, else `"Athena"`, and no
994
- initials are stored (`initials` then reads `None`). The SDK raises
1025
+ `""`) the author is `Document.user_name`, else the signed-in user agora's
1026
+ access check names as an agent writes for them, "Jane Doe (Athena)" (the
1027
+ author of the batch's tracked changes), else `"Athena"`, and no initials are stored (`initials` then reads `None`). The SDK raises
995
1028
  `ValueError` for what lxml refuses in an attribute, as python-docx
996
1029
  does, and also past docx-studio's caps (255 UTF-16 code units for an
997
1030
  author, 32 for initials); docx-studio turns tabs, line breaks and other
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.29.0
3
+ Version: 0.30.0
4
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>
@@ -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.29.0"
9
+ __version__ = "0.30.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -4,7 +4,8 @@ Wire format (matches ``apps/api/src/commands/types.ts``):
4
4
 
5
5
  POST /docs/:id/commands
6
6
  {
7
- "client": {"type": "python-sdk", "version": "<x.y.z>", "capabilities": ["trackedAuthoring"]},
7
+ "client": {"type": "python-sdk", "version": "<x.y.z>",
8
+ "capabilities": ["trackedAuthoring", "trackedMinimalParagraphText"]},
8
9
  "commands": [
9
10
  {"type": "CreateParagraph", "text": "Hi", "at": {"kind": "documentEnd"}},
10
11
  ...
@@ -42,7 +43,7 @@ from urllib3.util.retry import Retry
42
43
 
43
44
  from docx._batching import call_abandoned, note_progress
44
45
  from docx._buffer import CommandBuffer
45
- from docx._tracked import TRACKED_AUTHORING_CAPABILITY
46
+ from docx._tracked import TRACKED_AUTHORING_CAPABILITY, TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY
46
47
  from docx._timeouts import (
47
48
  DEFAULT_OP_TIMEOUT_SECONDS,
48
49
  LONG_RUNNING_COMMAND_TIMEOUT_SECONDS,
@@ -89,6 +90,7 @@ from docx.commands import (
89
90
  CreateTOC,
90
91
  CreateWatermark,
91
92
  DeleteBookmark,
93
+ DeleteParagraph,
92
94
  DeleteWatermark,
93
95
  EndnotesDelete,
94
96
  EndnotesGet,
@@ -1194,8 +1196,13 @@ class HttpClient:
1194
1196
  "client": {
1195
1197
  "type": "python-sdk",
1196
1198
  "version": _sdk_version(),
1197
- # Keeps its offsets as a tracked edit moves them (``docx._tracked``).
1198
- "capabilities": [TRACKED_AUTHORING_CAPABILITY],
1199
+ # Keeps its offsets as a tracked edit moves them, and reads a
1200
+ # paragraph's length back after a tracked ``paragraph.text``
1201
+ # (``docx._tracked``).
1202
+ "capabilities": [
1203
+ TRACKED_AUTHORING_CAPABILITY,
1204
+ TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY,
1205
+ ],
1199
1206
  },
1200
1207
  "commands": [
1201
1208
  _with_real_ids(c.to_dict(), ids) if ids else c.to_dict() for c in commands
@@ -1475,6 +1482,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
1475
1482
  "sections.set_columns": SetSectionColumns,
1476
1483
  "find_replace": FindReplace,
1477
1484
  "clear_body": ClearBody,
1485
+ "delete_paragraph": DeleteParagraph,
1478
1486
  "find_text": FindText,
1479
1487
  "iter_runs": IterRuns,
1480
1488
  "export_pdf": ExportPDF,
@@ -520,6 +520,15 @@ class PostExportOps:
520
520
  or bool(self._row_cant_split_ops)
521
521
  )
522
522
 
523
+ def forget_captured_refs(self) -> None:
524
+ """Drop the captured REF paragraphs (``Paragraph.delete``).
525
+
526
+ They are addressed by their index among the body's paragraphs, which
527
+ a deleted paragraph shifts, so a capture could restore over the
528
+ paragraph after the one it was taken from.
529
+ """
530
+ self._captured_refs.clear()
531
+
523
532
  def discard_body_ops(self) -> None:
524
533
  """Drop every rewrite that addresses body content by position.
525
534
 
@@ -1402,6 +1411,17 @@ def _count_ref_fields(p: ET.Element) -> int:
1402
1411
  return count
1403
1412
 
1404
1413
 
1414
+ _REVISION_TAGS = frozenset(
1415
+ f"{W_NS}{name}" for name in ("ins", "del", "moveFrom", "moveTo", "delInstrText")
1416
+ )
1417
+
1418
+
1419
+ def _holds_revisions(p: ET.Element) -> bool:
1420
+ """True when the paragraph holds tracked-change markup: an insertion,
1421
+ a deletion or a move, of its runs or of its paragraph mark."""
1422
+ return any(el.tag in _REVISION_TAGS for el in p.iter())
1423
+
1424
+
1405
1425
  def _iter_captured_ref_paragraphs(
1406
1426
  body: ET.Element,
1407
1427
  ) -> "Iterable[CapturedRefParagraph]":
@@ -1503,6 +1523,11 @@ def _restore_stripped_refs(
1503
1523
  if _count_ref_fields(exported) >= entry.ref_count:
1504
1524
  # DOCX Studio kept the REFs; nothing to do.
1505
1525
  continue
1526
+ if _holds_revisions(exported):
1527
+ # A tracked change (a deleted paragraph's REF is a
1528
+ # ``w:delInstrText`` in a ``w:del``) is an edit, not a strip:
1529
+ # restoring the source would drop it from the export.
1530
+ continue
1506
1531
  if _paragraph_fingerprint(exported) != entry.fingerprint:
1507
1532
  # The paragraph diverged on round-trip — user edited it or
1508
1533
  # DOCX Studio materially changed its text. Skip rather than
@@ -11,6 +11,13 @@ text in place.
11
11
  The SDK declares that it keeps its offsets this way
12
12
  (:data:`TRACKED_AUTHORING_CAPABILITY` in ``client.capabilities``); a
13
13
  docx-studio records a python-sdk's tracked edits only from an SDK that does.
14
+
15
+ A tracked ``paragraph.text = value`` is the exception: docx-studio marks only
16
+ the words that change (the words the old and new text share at their start
17
+ and end stay as they are), so the paragraph's new length is known only to the
18
+ server. The SDK forgets the length and reads it back before the next edit
19
+ that needs it, and says so (:data:`TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY`);
20
+ a docx-studio replaces the whole text for an SDK that does not.
14
21
  """
15
22
 
16
23
  from __future__ import annotations
@@ -20,6 +27,10 @@ from typing import Any
20
27
  #: What the SDK tells docx-studio in ``client.capabilities`` on every batch.
21
28
  TRACKED_AUTHORING_CAPABILITY = "trackedAuthoring"
22
29
 
30
+ #: Also sent: the SDK reads a paragraph's length back after a tracked
31
+ #: ``paragraph.text = value``, so docx-studio may mark only what changes.
32
+ TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY = "trackedMinimalParagraphText"
33
+
23
34
 
24
35
  def tracking(session: Any) -> bool:
25
36
  """True when ``session``'s writes go out with ``changeMode: "tracked"``
@@ -781,8 +781,8 @@ class CommentsCreate(Command):
781
781
  target: dict[str, Any] | None = None
782
782
  parent_id: str | None = None
783
783
  # Word's ``w:author`` / ``w:initials`` (display text). Left unset, the
784
- # comment's author is the batch's ``user.name``, else "Athena", and it
785
- # has no initials.
784
+ # comment's author is the batch's ``user.name``, else the user agora's
785
+ # access check names, else "Athena", and it has no initials.
786
786
  author: str | None = None
787
787
  initials: str | None = None
788
788
  # Optional client-assigned entity id for transparent-batched
@@ -1770,6 +1770,19 @@ class ClearBody(Command):
1770
1770
  """
1771
1771
 
1772
1772
 
1773
+ @dataclass
1774
+ class DeleteParagraph(Command):
1775
+ """Delete a whole body paragraph (:meth:`Paragraph.delete`).
1776
+
1777
+ Athena extension: python-docx has no paragraph delete. Direct, DOCX Studio
1778
+ removes the paragraph; with ``track_revisions`` it keeps it as Word's
1779
+ tracked deletion of its content and its paragraph mark, fields included,
1780
+ which Accept All removes and Reject All restores. Returns ``{changed}``.
1781
+ """
1782
+
1783
+ block_id: str = ""
1784
+
1785
+
1773
1786
  @dataclass
1774
1787
  class FindText(Command):
1775
1788
  """Search document text and return bounded match context.
@@ -2003,6 +2016,9 @@ _RESPONSE_BEARING_TYPES: frozenset[str] = frozenset(
2003
2016
  # ClearBody replaces the whole body; Document.clear awaits it so a
2004
2017
  # rejected clear raises instead of leaving stale content behind.
2005
2018
  "ClearBody",
2019
+ # DeleteParagraph returns {changed}; Paragraph.delete awaits it so a
2020
+ # refused delete raises at the call.
2021
+ "DeleteParagraph",
2006
2022
  # TablesMergeCells returns the merged cell, which ``_Cell.merge``
2007
2023
  # returns; an invalid span raises InvalidSpanError at the call, as in
2008
2024
  # python-docx.
@@ -2104,6 +2120,7 @@ for _cls, _issue, _desc in [
2104
2120
  (SetSectionColumns, "python-docx#167", "Section multi-column layout"),
2105
2121
  (FindReplace, "python-docx#30", "Formatting-preserving find/replace"),
2106
2122
  (ClearBody, None, "Document.clear — bulk body reset"),
2123
+ (DeleteParagraph, "python-docx#33", "Paragraph.delete — whole paragraph delete"),
2107
2124
  (FindText, "python-docx#980", "Fast document text search"),
2108
2125
  (IterRuns, "python-docx#980", "Run stream for run-isolation"),
2109
2126
  (ExportPDF, "python-docx#113", "PDF export"),
@@ -2247,6 +2264,7 @@ __all__ = [
2247
2264
  "SetSectionColumns",
2248
2265
  "FindReplace",
2249
2266
  "ClearBody",
2267
+ "DeleteParagraph",
2250
2268
  "FindText",
2251
2269
  "IterRuns",
2252
2270
  "ExportPDF",
@@ -216,7 +216,8 @@ def _comment_display_fields(
216
216
  so does docx-studio, as display text only: Keryx attributes the write
217
217
  itself to the signed-in user (and agent). An empty author, python-docx's
218
218
  default, is not sent, so the comment keeps the session's name
219
- (``Document.user_name``, else "Athena"); empty or ``None`` initials are
219
+ (``Document.user_name``, else the signed-in user, else "Athena"); empty
220
+ or ``None`` initials are
220
221
  not sent either. docx-studio turns tabs, line breaks and other control
221
222
  characters into spaces.
222
223
  """
@@ -492,7 +493,8 @@ class Comments:
492
493
  ``w:initials``. They are display text; the edit itself is
493
494
  attributed to the signed-in user. Without an ``author`` the
494
495
  comment's author is the session's name (``Document.user_name``,
495
- else "Athena"). Use :meth:`Document.add_comment` to thread a
496
+ else the signed-in user, else "Athena"). Use
497
+ :meth:`Document.add_comment` to thread a
496
498
  run-anchored target — this method creates an unanchored comment.
497
499
  """
498
500
  # python-docx 1.x routes ``text`` / ``author`` / ``initials``
@@ -853,7 +853,8 @@ class Document:
853
853
  ``initials`` as Word's ``w:author`` / ``w:initials`` (display
854
854
  text; the edit itself is attributed to the signed-in user). Without
855
855
  an ``author`` its author is the session's name
856
- (:attr:`user_name`, else "Athena"). The runs must be co-located in
856
+ (:attr:`user_name`, else the signed-in user, else "Athena"). The
857
+ runs must be co-located in
857
858
  a single block (Word can't anchor a comment to disjoint blocks); if
858
859
  they span multiple blocks the comment is created unanchored.
859
860
  """
@@ -11,6 +11,10 @@ from docx._batching import run_sync
11
11
  from docx._run_order import forget_paragraph, register_run
12
12
  from docx._tracked import tracking
13
13
 
14
+ #: The session attribute ``Paragraph.delete`` bumps, after which every
15
+ #: paragraph handle of the session reads its list number again.
16
+ _NUMBERING_GENERATION_ATTR = "_docx_numbering_generation"
17
+
14
18
  if TYPE_CHECKING:
15
19
  from docx._references import AssetReference
16
20
  from docx.bookmarks import Bookmark
@@ -675,8 +679,10 @@ class Paragraph:
675
679
  )
676
680
  # We just replaced the entire paragraph contents with ``value``;
677
681
  # the new text-address length is simply ``len(value)``. With tracking
678
- # on the old text stays, deleted, before ``value`` (``docx._tracked``).
679
- self._text_len = current_len + len(value) if tracked else len(value)
682
+ # on docx-studio keeps the words the old and new text share and marks
683
+ # only the rest, so only the server knows the length: read it back
684
+ # before the next edit that needs it (``docx._tracked``).
685
+ self._text_len = None if tracked else len(value)
680
686
  # The runs of the paragraph are gone, as in python-docx.
681
687
  forget_paragraph(self)
682
688
  # Content changed — drop the prefetched snapshot so a follow-up
@@ -2141,8 +2147,77 @@ class Paragraph:
2141
2147
  )
2142
2148
  self._list_info_cache = None
2143
2149
 
2150
+ @athena_extension(
2151
+ issue=33,
2152
+ since="0.30.0",
2153
+ description="Paragraph.delete — delete the whole paragraph, as a tracked deletion with track_revisions.",
2154
+ )
2155
+ def delete(self) -> None:
2156
+ """Delete this paragraph from the document, its paragraph mark included.
2157
+
2158
+ python-docx has no paragraph delete (issue #33); code written for it
2159
+ removes the element, ``p._element.getparent().remove(p._element)``,
2160
+ which this SDK cannot reach. ``paragraph.delete()`` does that here::
2161
+
2162
+ for p in doc.paragraphs:
2163
+ if p.text.startswith("Forfeiture of Rights"):
2164
+ p.delete()
2165
+
2166
+ With tracking off the paragraph goes. With ``track_revisions`` on it
2167
+ is Word's tracked deletion of a whole paragraph: all its content, its
2168
+ cross-reference and other fields, links and note references included,
2169
+ and its paragraph mark, one change by the signed-in user. Accept All
2170
+ removes the paragraph and the numbered paragraphs after it number on;
2171
+ Reject All gives it back as it was. Setting ``p.text = ""`` instead
2172
+ leaves an empty (still numbered) paragraph behind.
2173
+
2174
+ The delete goes in a request of its own, after the edits buffered
2175
+ before it, so a refused one takes none of them down.
2176
+
2177
+ Raises:
2178
+ DocxError: docx-studio refused the delete, and changed nothing:
2179
+ ``ParagraphDeleteRefused`` for the document's last paragraph
2180
+ (Word never deletes its mark), one that ends a section, the
2181
+ only paragraph of a table cell or content control, one holding
2182
+ part of a field that spans paragraphs, and one in a header,
2183
+ footer, comment or text box; with tracking on,
2184
+ ``TrackedChangesUnsupported`` for one in a table cell or holding
2185
+ a page break, a content control, a shape or an equation.
2186
+ """
2187
+ from docx.commands import DeleteParagraph
2188
+
2189
+ self._adopt_cell_paragraph()
2190
+ run_sync(self._session.save())
2191
+ run_sync(self._session.send_command(DeleteParagraph(block_id=self._node_id)))
2192
+ # The template's REF paragraphs are restored on export by their body
2193
+ # index (``docx._postproc``), which this delete may have shifted.
2194
+ post_export_ops: object = getattr(self._session, "_post_export_ops", None)
2195
+ forget = getattr(post_export_ops, "forget_captured_refs", None)
2196
+ if callable(forget):
2197
+ forget()
2198
+ # Every handle's list number is read again: the items after this one renumber.
2199
+ generation: object = getattr(self._session, _NUMBERING_GENERATION_ATTR, 0)
2200
+ next_generation = (generation if isinstance(generation, int) else 0) + 1
2201
+ try:
2202
+ setattr(self._session, _NUMBERING_GENERATION_ATTR, next_generation)
2203
+ except AttributeError: # a session that takes no new attribute
2204
+ pass
2205
+ self._text_len = None
2206
+ forget_paragraph(self)
2207
+ self._invalidate_node_info()
2208
+ self._list_info_cache = None
2209
+
2144
2210
  def _list_info(self) -> dict | None:
2145
- """Cache-then-fetch the numbering record for this paragraph."""
2211
+ """Cache-then-fetch the numbering record for this paragraph.
2212
+
2213
+ The cache holds until a paragraph of the session is deleted
2214
+ (:meth:`delete` bumps the session's numbering generation): the list
2215
+ items after it number again, so every handle reads its number anew.
2216
+ """
2217
+ generation: object = getattr(self._session, _NUMBERING_GENERATION_ATTR, 0)
2218
+ if getattr(self, "_list_info_generation", 0) != generation:
2219
+ self._list_info_cache = None
2220
+ self._list_info_generation = generation
2146
2221
  cache = getattr(self, "_list_info_cache", None)
2147
2222
  if cache is not None:
2148
2223
  return cache or None
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.29.0"
7
+ version = "0.30.0"
8
8
  description = "Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -173,6 +173,7 @@
173
173
  "fixture-bookmarks-internal-links",
174
174
  "fixture-breaks-inline",
175
175
  "fixture-breaks-tabs",
176
+ "fixture-character-style-toggles",
176
177
  "fixture-chart-column",
177
178
  "fixture-cjk-grid-theme-colors",
178
179
  "fixture-comments-links",
@@ -253,10 +254,5 @@
253
254
  "rw16_header_footer_tables",
254
255
  "rw17_header_letterhead_filled"
255
256
  ],
256
- "gaps": [
257
- "fixture-headers-tabs-wrapped::reads::sections.header.paragraphs",
258
- "fixture-tables-content-controls::reads::tables.cell_format",
259
- "fixture-tables-content-controls::reads::tables.cells",
260
- "fixture-tables-content-controls::reads::tables.rows"
261
- ]
257
+ "gaps": []
262
258
  }
@@ -113,6 +113,7 @@ _EXPECTED_LOCATIONS: set[str] = {
113
113
  "docx.text.paragraph.Paragraph.list_format",
114
114
  "docx.text.paragraph.Paragraph.list_number",
115
115
  "docx.text.paragraph.Paragraph.restart_numbering",
116
+ "docx.text.paragraph.Paragraph.delete",
116
117
  # Run methods.
117
118
  "docx.text.run.Run.add_field",
118
119
  "docx.text.run.Run.add_footnote",
@@ -89,7 +89,7 @@ def test_path_proxy_walks_dotted_path() -> None:
89
89
  assert body["client"] == {
90
90
  "type": "python-sdk",
91
91
  "version": SDK_VERSION,
92
- "capabilities": ["trackedAuthoring"],
92
+ "capabilities": ["trackedAuthoring", "trackedMinimalParagraphText"],
93
93
  }
94
94
  assert body["return"] == {"snapshot": False}
95
95
  assert body["commands"] == [