athena-python-docx 0.21.8__tar.gz → 0.22.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 (372) hide show
  1. athena_python_docx-0.21.8/CLAUDE.md → athena_python_docx-0.22.0/AGENTS.md +37 -3
  2. athena_python_docx-0.22.0/CLAUDE.md +5 -0
  3. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/DOCX_EXEC_LAB.md +1 -1
  4. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/PKG-INFO +2 -2
  5. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/README.md +1 -1
  6. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/__init__.py +1 -1
  7. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_buffer.py +2 -2
  8. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_http.py +1 -1
  9. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_http_doc.py +2 -0
  10. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_postproc.py +21 -0
  11. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_ptc.py +74 -8
  12. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_timeouts.py +3 -0
  13. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/client.py +5 -1
  14. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/commands.py +23 -2
  15. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/document.py +39 -70
  16. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/table.py +78 -1
  17. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/paragraph.py +14 -9
  18. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/run.py +3 -0
  19. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/pyproject.toml +1 -1
  20. athena_python_docx-0.22.0/scripts/release.sh +14 -0
  21. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/README.md +1 -1
  22. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/__init__.py +1 -1
  23. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/ab_probe_cases.py +1 -1
  24. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/binary_round_trip.py +1 -1
  25. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/cases.py +1 -1
  26. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/fake_session.py +1 -1
  27. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/local_runner.py +1 -1
  28. athena_python_docx-0.22.0/tests/test_athena_extension_creates_session_open.py +64 -0
  29. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_athena_extensions_registry.py +2 -0
  30. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_citations.py +120 -0
  31. athena_python_docx-0.22.0/tests/test_document_clear.py +277 -0
  32. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_execution_scope.py +1 -1
  33. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_ptc.py +105 -1
  34. athena_python_docx-0.22.0/tests/test_run_mark_inheritance.py +88 -0
  35. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_wire_contract.py +1 -0
  36. athena_python_docx-0.21.8/scripts/publish.sh +0 -37
  37. athena_python_docx-0.21.8/scripts/release.sh +0 -84
  38. athena_python_docx-0.21.8/tests/test_document_clear.py +0 -132
  39. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/.gitignore +0 -0
  40. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_athena_extension.py +0 -0
  41. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_batching.py +0 -0
  42. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_citations.py +0 -0
  43. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_execution.py +0 -0
  44. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_image_utils.py +0 -0
  45. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_references.py +0 -0
  46. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/_table_styles.py +0 -0
  47. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/api.py +0 -0
  48. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/bookmarks.py +0 -0
  49. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/charts.py +0 -0
  50. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/comments.py +0 -0
  51. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/__init__.py +0 -0
  52. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/section.py +0 -0
  53. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/shape.py +0 -0
  54. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/style.py +0 -0
  55. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/table.py +0 -0
  56. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/enum/text.py +0 -0
  57. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/errors.py +0 -0
  58. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/exceptions.py +0 -0
  59. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/fields.py +0 -0
  60. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/footnotes.py +0 -0
  61. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/math.py +0 -0
  62. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/opc/__init__.py +0 -0
  63. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/opc/coreprops.py +0 -0
  64. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/oxml/__init__.py +0 -0
  65. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/revisions.py +0 -0
  66. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/sdt.py +0 -0
  67. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/section.py +0 -0
  68. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/session.py +0 -0
  69. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/settings.py +0 -0
  70. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/shape.py +0 -0
  71. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/shared.py +0 -0
  72. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/styles/__init__.py +0 -0
  73. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/styles/style.py +0 -0
  74. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/styles/styles.py +0 -0
  75. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/__init__.py +0 -0
  76. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/font.py +0 -0
  77. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/hyperlink.py +0 -0
  78. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/pagebreak.py +0 -0
  79. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/parfmt.py +0 -0
  80. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/text/tabstops.py +0 -0
  81. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/toc.py +0 -0
  82. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/docx/typing.py +0 -0
  83. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/docx_exec_lab.py +0 -0
  84. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  85. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  86. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/docx_exec_lab_server.py +0 -0
  87. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/dump_wire_fixtures.py +0 -0
  88. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/round_trip_smoke.py +0 -0
  89. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/smoke_test_block_not_found.py +0 -0
  90. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/scripts/validate_find_replace_asset.py +0 -0
  91. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/__init__.py +0 -0
  92. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/conftest.py +0 -0
  93. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/METHODOLOGY.md +0 -0
  94. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/ab_probe_runner.py +0 -0
  95. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/auto_gen_cases.py +0 -0
  96. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/complex_cases.py +0 -0
  97. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/coverage_report.py +0 -0
  98. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/extract.py +0 -0
  99. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/extreme_cases.py +0 -0
  100. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/README.md +0 -0
  101. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  102. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  103. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  104. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  105. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  106. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/mega_cases.py +0 -0
  107. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshot.py +0 -0
  108. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  109. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  110. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  111. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  112. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  113. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  114. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  115. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  116. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  117. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  118. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  119. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  120. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  121. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  122. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  123. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  124. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  125. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  126. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  127. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  128. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  129. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  130. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  131. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  132. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  133. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  134. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  135. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  136. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  137. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  138. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  139. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  140. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  141. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  142. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  143. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  144. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  145. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  146. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  147. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  148. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  149. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  150. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  151. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  152. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  153. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  154. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  155. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  156. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  157. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  158. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  159. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  160. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  161. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  162. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  163. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  164. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  165. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  166. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  167. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  168. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  169. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  170. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  171. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  172. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  173. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  174. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  175. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  176. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  177. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  178. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  179. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  180. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  181. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  182. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  183. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  184. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  185. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  186. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  187. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  188. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  189. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  190. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  191. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  192. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  193. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  194. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  195. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  196. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  197. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  198. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  199. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  200. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  201. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  202. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  203. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  204. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  205. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  206. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  207. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  208. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  209. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  210. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  211. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  212. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  213. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  214. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  215. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  216. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  217. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  218. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  219. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  220. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  221. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  222. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  223. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  224. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  225. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  226. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  227. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  228. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  229. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  230. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  231. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  232. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  233. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  234. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  235. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  236. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  237. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  238. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  239. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  240. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  241. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  242. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  243. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  244. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  245. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  246. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  247. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  248. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  249. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  250. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  251. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  252. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  253. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  254. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  255. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/ours_spec.json +0 -0
  256. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/parity_crawl.py +0 -0
  257. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/parity_diff.json +0 -0
  258. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/real_world_cases.py +0 -0
  259. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/round_trip_tests.py +0 -0
  260. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/stock_spec.json +0 -0
  261. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  262. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/README.md +0 -0
  263. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/__init__.py +0 -0
  264. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/baseline_gaps.json +0 -0
  265. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/compare.py +0 -0
  266. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/intentional_deviations.json +0 -0
  267. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/introspect.py +0 -0
  268. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  269. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/reports/gap_report.json +0 -0
  270. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/run_parity.py +0 -0
  271. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/snapshots/athena_latest.json +0 -0
  272. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  273. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/parity/test_parity_gap.py +0 -0
  274. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_add_section_extract_items.py +0 -0
  275. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_athena_extensions_contract.py +0 -0
  276. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_batching_perf.py +0 -0
  277. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_block_not_found_error.py +0 -0
  278. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_buffer.py +0 -0
  279. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  280. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_add_table_not_supported.py +0 -0
  281. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_fastpath_runs.py +0 -0
  282. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  283. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  284. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_inner_format_stash.py +0 -0
  285. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  286. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_inner_run_guard.py +0 -0
  287. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  288. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_cell_text_replace_semantics.py +0 -0
  289. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_collapsed_range_format.py +0 -0
  290. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_command_dataclasses.py +0 -0
  291. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_commands.py +0 -0
  292. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_comments.py +0 -0
  293. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_document_asset_id_property.py +0 -0
  294. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_document_create.py +0 -0
  295. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_document_create_from_template.py +0 -0
  296. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_document_factory_validation.py +0 -0
  297. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_docx_exec_lab.py +0 -0
  298. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_docx_exec_lab_server.py +0 -0
  299. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  300. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_find_replace_session_open.py +0 -0
  301. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_http_transport.py +0 -0
  302. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_hyperlink_coalescing.py +0 -0
  303. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_image_url_data_uri.py +0 -0
  304. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_insert_deferred.py +0 -0
  305. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_iter_inner_content.py +0 -0
  306. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_list_styles.py +0 -0
  307. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  308. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_merged_cells.py +0 -0
  309. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_oxml_shim.py +0 -0
  310. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_paragraph_text_len_cache.py +0 -0
  311. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_parity_misc.py +0 -0
  312. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_parity_round2.py +0 -0
  313. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_partial_failure_cascade.py +0 -0
  314. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_phase_a_behavior.py +0 -0
  315. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_phase_b_headers_footers.py +0 -0
  316. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_phase_c_tables.py +0 -0
  317. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_positional_cell_id.py +0 -0
  318. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  319. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  320. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_postproc_ref_restore.py +0 -0
  321. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_pr19766_review_fixes.py +0 -0
  322. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_python_docx_api_parity.py +0 -0
  323. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_revisions.py +0 -0
  324. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_run_add_picture_anchor.py +0 -0
  325. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  326. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_add_picture.py +0 -0
  327. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_add_run.py +0 -0
  328. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  329. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  330. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_comments_get.py +0 -0
  331. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_document_audit.py +0 -0
  332. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_document_element.py +0 -0
  333. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_enum_section.py +0 -0
  334. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_font_audit.py +0 -0
  335. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_header_footer.py +0 -0
  336. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_hyperlink.py +0 -0
  337. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_inline_shape.py +0 -0
  338. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  339. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_misc.py +0 -0
  340. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  341. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  342. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  343. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_parfmt.py +0 -0
  344. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  345. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_add_break.py +0 -0
  346. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  347. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_style.py +0 -0
  348. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  349. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_text.py +0 -0
  350. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_run_underline.py +0 -0
  351. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_section_audit.py +0 -0
  352. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  353. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_section_onoff.py +0 -0
  354. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_settings.py +0 -0
  355. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_shared_audit.py +0 -0
  356. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_style.py +0 -0
  357. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_styles.py +0 -0
  358. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_table_audit.py +0 -0
  359. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_table_cell.py +0 -0
  360. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  361. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_silent_stub_table_layout.py +0 -0
  362. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_smoke_integration.py +0 -0
  363. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_style_acceptance.py +0 -0
  364. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_style_font.py +0 -0
  365. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_style_setters_contract.py +0 -0
  366. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_table_set_cell_perf.py +0 -0
  367. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_table_style_id_resolution.py +0 -0
  368. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_temporarily_unavailable.py +0 -0
  369. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  370. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_xml_attr_guard.py +0 -0
  371. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/tests/test_zod_wire_contract.py +0 -0
  372. {athena_python_docx-0.21.8 → athena_python_docx-0.22.0}/uv.lock +0 -0
@@ -367,8 +367,8 @@ Issue numbers reference `python-openxml/python-docx`.
367
367
  list metadata. Routes through `NumberingGet`.
368
368
 
369
369
  - **`Document.to_pdf(*, quality=None, destination=None,
370
- include_revisions=False) -> bytes`** — render to PDF via the
371
- Daytona-hosted LibreOffice. python-docx issue #113 was closed as
370
+ include_revisions=False) -> bytes`** — render to PDF. python-docx
371
+ issue #113 was closed as
372
372
  wontfix upstream but the request keeps recurring. Routes through
373
373
  `ExportPDF` (DOCX Studio handles the actual conversion).
374
374
 
@@ -447,6 +447,40 @@ Issue numbers reference `python-openxml/python-docx`.
447
447
  only when you already have a DOCX editor anchor id. For normal writing,
448
448
  cite the ``Paragraph`` proxy you just created or found.
449
449
 
450
+ - **Table-cell citations** (0.22.0+): **`_Cell.add_citation(source, *,
451
+ anchor=None, citation_string=None, excerpt=None, display_value=None)
452
+ -> str`** + **`_Cell.clear_citations()`**, and ``Paragraph.add_citation``
453
+ / ``Paragraph.clear_citations`` on cell paragraphs (before 0.22.0 they
454
+ raised ``ValueError`` "top-level DOCX paragraphs only"). The SDK models a
455
+ cell as one paragraph addressed by the synthetic cell id
456
+ (``tc:table:row:col``; ``cell.paragraphs[0]`` stands for the whole cell),
457
+ so a cell citation sends that id. The docx-studio applier resolves it to
458
+ the cell's paragraph ids: one paragraph with text → ``pm_node``, several
459
+ → ``pm_node_range`` from the first to the last; a cell paragraph with no
460
+ paraId (or a repeated one) gets a new one. A horizontally merged cell
461
+ resolves to its master cell from any grid position it covers. A
462
+ paragraph that ``cell.add_paragraph(text)`` returned already carries its
463
+ own paraId and is cited alone. To cite one paragraph of a cell (or a
464
+ paragraph in a nested table), pass the ``data-id`` a Word read shows for
465
+ it: ``doc.add_citation(..., destination_anchor=PmNodeAnchor(node_id=...))``.
466
+ ``_Cell.clear_citations()`` removes every citation inside the cell.
467
+ Write the cell text first, then cite it:
468
+
469
+ ```python
470
+ table = doc.add_table(rows=2, cols=2)
471
+ table.cell(1, 0).text = "Revenue"
472
+ table.cell(1, 1).text = "$12.4M"
473
+ table.cell(1, 1).add_citation(
474
+ "/dashboard/spaces/?asset_ids=asset_sheet&type=spreadsheet"
475
+ "&anchor=sheet_range&sheet_id=0&range=C4",
476
+ excerpt="$12.4M",
477
+ )
478
+ ```
479
+
480
+ Needs a docx-studio API that resolves cell ids (the same release train);
481
+ an older API stores the record under the cell id, where nothing renders
482
+ it and the next edit retires it.
483
+
450
484
  - **`Document.export_docx(path=None, *, include_revisions=False)
451
485
  -> bytes`** (0.11.4+) — export the document's current state as
452
486
  ``.docx`` bytes, optionally writing to ``path``. Closes the gap
@@ -769,7 +803,7 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
769
803
  drain pending ops before running; the 100 ms idle timer fires on
770
804
  inactivity so collab updates stream live; `Document.save()` and
771
805
  the context-manager exit drain explicitly; `docx.flush_all()` is
772
- the Daytona-prelude hook that flushes every live buffer in the
806
+ the executor-postamble hook that flushes every live buffer in the
773
807
  process.
774
808
  - Execution scope: executor sandboxes may keep Python globals
775
809
  between tool calls so imports, constants, and helper functions can be
@@ -0,0 +1,5 @@
1
+ @AGENTS.md
2
+
3
+ <!-- AGENTS.md next to this file is the single source of truth for agent
4
+ instructions. Claude Code does not read AGENTS.md natively, so this file
5
+ imports it. Add Claude-Code-only rules below this line. -->
@@ -6,7 +6,7 @@ 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.
8
8
 
9
- Use this before waiting on a full Agent -> Daytona -> preview cycle when
9
+ Use this before waiting on a full Agent -> executor sandbox -> preview cycle when
10
10
  debugging SDK behavior such as large-document replacement, table fills,
11
11
  unsupported OOXML internals, or export fidelity.
12
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.21.8
3
+ Version: 0.22.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>
@@ -76,7 +76,7 @@ an Olympus Word document embed preview pane. See `DOCX_EXEC_LAB.md`.
76
76
 
77
77
  ## Environment variables
78
78
 
79
- Required when connecting to DOCX Studio (set by Athena backend when executing in Daytona):
79
+ Required when connecting to DOCX Studio (set by the Athena backend in the `execute_word_document_code` executor sandbox):
80
80
 
81
81
  - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
82
82
  - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
@@ -51,7 +51,7 @@ 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 DOCX Studio (set by Athena backend when executing in Daytona):
54
+ Required when connecting to DOCX Studio (set by the Athena backend in the `execute_word_document_code` executor sandbox):
55
55
 
56
56
  - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
57
57
  - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
@@ -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.21.8"
9
+ __version__ = "0.22.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -20,7 +20,7 @@ guard the pending list with an RLock and treat the timer flush as a
20
20
  best-effort coalesce — if the loop thread races us we just flush twice
21
21
  (or zero times; the next loop-thread call drains it).
22
22
 
23
- `flush_all` is a process-wide hook used by the Daytona sandbox prelude to
23
+ `flush_all` is a process-wide hook used by Athena's sandbox executor to
24
24
  make sure pending writes hit Keryx before the sandbox is suspended. It walks
25
25
  a weak-ref registry so dead Workbook instances don't keep their buffers
26
26
  alive.
@@ -199,7 +199,7 @@ def _unregister(buffer: "CommandBuffer") -> None:
199
199
  def flush_all(*, strict: bool = False) -> None:
200
200
  """Flush every live CommandBuffer in this process.
201
201
 
202
- Used by the Daytona sandbox prelude after user code returns, so
202
+ Used by Athena's sandbox executor after user code returns, so
203
203
  buffered mutations make it to Keryx before the sandbox is suspended.
204
204
  Safe to call when no Buffers exist (no-op).
205
205
 
@@ -5,7 +5,7 @@ bootstrap and upload calls on urllib so ``Document.create()`` can provision
5
5
  Word document assets without pulling in extra runtime dependencies.
6
6
 
7
7
  We use ``urllib`` from stdlib to avoid pulling ``httpx`` / ``requests``
8
- into the runtime — this code runs in Daytona sandboxes where every MB
8
+ into the runtime — this code runs in sandboxes where every MB
9
9
  matters, and the existing SDK already keeps its dep tree tight.
10
10
  """
11
11
 
@@ -46,6 +46,7 @@ from docx.commands import (
46
46
  BookmarksList,
47
47
  ChartsGet,
48
48
  ChartsList,
49
+ ClearBody,
49
50
  ClearParagraphAlignment,
50
51
  ClearParagraphIndentation,
51
52
  ClearParagraphSpacing,
@@ -1002,6 +1003,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
1002
1003
  "sdt.delete": ContentControlsDelete,
1003
1004
  "sections.set_columns": SetSectionColumns,
1004
1005
  "find_replace": FindReplace,
1006
+ "clear_body": ClearBody,
1005
1007
  "find_text": FindText,
1006
1008
  "iter_runs": IterRuns,
1007
1009
  "export_pdf": ExportPDF,
@@ -497,6 +497,27 @@ class PostExportOps:
497
497
  or bool(self._row_cant_split_ops)
498
498
  )
499
499
 
500
+ def discard_body_ops(self) -> None:
501
+ """Drop every rewrite that addresses body content by position.
502
+
503
+ Cell/table formatting, row heights, captured REF paragraphs and
504
+ header/footer relocations are all keyed by body-relative indices
505
+ (``table_doc_index``, ``source_paragraph_index``, body node ids).
506
+ Once the body story has been replaced they point at nodes that no
507
+ longer exist — and would silently re-target whatever the caller
508
+ creates next at the same index. Document-wide rewrites
509
+ (``font_override``) do not address the body and are kept.
510
+ """
511
+ self._cell_format_ops.clear()
512
+ self._cell_run_format_ops.clear()
513
+ self._cell_hyperlink_ops.clear()
514
+ self._cell_shading_ops.clear()
515
+ self._table_borders_ops.clear()
516
+ self._captured_refs.clear()
517
+ self._row_height_ops.clear()
518
+ self._row_cant_split_ops.clear()
519
+ self._header_footer_relocations.clear()
520
+
500
521
  def add_row_cant_split(
501
522
  self,
502
523
  *,
@@ -23,6 +23,11 @@ Emits are **synchronous, best-effort** HTTP POSTs:
23
23
  - Snapshot the URL at ``emit_begin`` time and carry it to ``emit_end``
24
24
  so late end events can't be misattributed if a new sandbox run
25
25
  swapped in a different URL between begin and end.
26
+ - Reuse one keep-alive connection per endpoint instead of a new TCP (and
27
+ TLS) connection per event. An idle connection the server has closed is
28
+ detected before sending and replaced; a send is never retried (the
29
+ registry does not deduplicate events). When a proxy applies to the URL
30
+ (``*_proxy`` env vars) each event goes through urllib as before.
26
31
 
27
32
  This module is *intentionally byte-identical* across the docx / pptx /
28
33
  xlsx SDKs — the three SDKs have no shared base. Duplicating ~100 LOC
@@ -31,10 +36,14 @@ of stdlib code is cheaper than spinning up a 4th release pipeline.
31
36
 
32
37
  from __future__ import annotations
33
38
 
39
+ import http.client
34
40
  import json
35
41
  import os
42
+ import select
43
+ import threading
36
44
  import time
37
45
  import urllib.error
46
+ import urllib.parse
38
47
  import urllib.request
39
48
  import uuid
40
49
  from typing import Any
@@ -46,6 +55,58 @@ _HTTP_TIMEOUT = 2.0
46
55
  # original run's endpoint even if ATHENA_PTC_URL changed since.
47
56
  _call_url: dict[str, str] = {}
48
57
 
58
+ # (scheme, host:port) -> an idle keep-alive connection. Checked out while a
59
+ # POST uses it, so no two threads ever share one.
60
+ _idle: dict[tuple[str, str], http.client.HTTPConnection] = {}
61
+ _idle_lock = threading.Lock()
62
+
63
+
64
+ def _dropped(conn: http.client.HTTPConnection) -> bool:
65
+ """An idle connection the server has closed (or that has unexpected data
66
+ waiting) reads as ready: never send on it."""
67
+ sock = conn.sock
68
+ if sock is None:
69
+ return True
70
+ try:
71
+ return bool(select.select([sock], [], [], 0)[0])
72
+ except (OSError, ValueError):
73
+ return True
74
+
75
+
76
+ def _post_keepalive(url: str, raw: bytes) -> None:
77
+ parts = urllib.parse.urlsplit(url)
78
+ if parts.scheme not in ("http", "https") or not parts.hostname:
79
+ raise ValueError(f"unsupported PTC URL: {url!r}")
80
+ target = (parts.path or "/") + (f"?{parts.query}" if parts.query else "")
81
+ key = (parts.scheme, parts.netloc)
82
+ with _idle_lock:
83
+ conn = _idle.pop(key, None)
84
+ if conn is not None and _dropped(conn):
85
+ conn.close()
86
+ conn = None
87
+ if conn is None:
88
+ factory = (
89
+ http.client.HTTPSConnection if parts.scheme == "https" else http.client.HTTPConnection
90
+ )
91
+ conn = factory(parts.netloc, timeout=_HTTP_TIMEOUT)
92
+ # Never retried: a failure after the request left may still have been
93
+ # processed, and the registry does not deduplicate events.
94
+ try:
95
+ conn.request("POST", target, body=raw, headers={"Content-Type": "application/json"})
96
+ response = conn.getresponse()
97
+ response.read()
98
+ except BaseException:
99
+ conn.close()
100
+ raise
101
+ if response.will_close:
102
+ conn.close()
103
+ return
104
+ with _idle_lock:
105
+ spare = _idle.pop(key, None)
106
+ _idle[key] = conn
107
+ if spare is not None:
108
+ spare.close()
109
+
49
110
 
50
111
  def _send(url: str, body: dict[str, Any]) -> None:
51
112
  """Synchronously POST one PTC event. Best-effort; never raises.
@@ -63,14 +124,19 @@ def _send(url: str, body: dict[str, Any]) -> None:
63
124
  key = "args" if body.get("phase") == "begin" else "result"
64
125
  body[key] = {"__truncated__": True}
65
126
  raw = json.dumps(body).encode("utf-8")
66
- req = urllib.request.Request(
67
- url,
68
- data=raw,
69
- method="POST",
70
- headers={"Content-Type": "application/json"},
71
- )
72
- urllib.request.urlopen(req, timeout=_HTTP_TIMEOUT).close()
73
- except (urllib.error.URLError, OSError, ValueError):
127
+ parts = urllib.parse.urlsplit(url)
128
+ proxy = urllib.request.getproxies().get(parts.scheme)
129
+ if proxy and not urllib.request.proxy_bypass(parts.hostname or ""):
130
+ req = urllib.request.Request(
131
+ url,
132
+ data=raw,
133
+ method="POST",
134
+ headers={"Content-Type": "application/json"},
135
+ )
136
+ urllib.request.urlopen(req, timeout=_HTTP_TIMEOUT).close()
137
+ else:
138
+ _post_keepalive(url, raw)
139
+ except (urllib.error.URLError, OSError, ValueError, http.client.HTTPException):
74
140
  pass # never propagate — PTC is best-effort
75
141
 
76
142
 
@@ -19,6 +19,9 @@ _LONG_RUNNING_COMMAND_TYPES: frozenset[str] = frozenset(
19
19
  # ordinary 60s budget committing a table batch even when the Python code
20
20
  # uses the fast no-read cell path.
21
21
  "TableSetCell",
22
+ # ``Document.clear()`` replaces the whole body story in one write;
23
+ # on a large document that single command can outlast the 60s budget.
24
+ "ClearBody",
22
25
  }
23
26
  )
24
27
 
@@ -36,7 +36,7 @@ if TYPE_CHECKING:
36
36
 
37
37
  def _log_info(msg: str) -> None:
38
38
  """Minimal stderr logger; we avoid loguru to keep the SDK runtime
39
- dependency tree small (this code runs inside Daytona sandboxes)."""
39
+ dependency tree small (this code runs inside sandboxes)."""
40
40
  import sys
41
41
 
42
42
  print(f"[docx-sdk] {msg}", file=sys.stderr)
@@ -84,6 +84,10 @@ class Session:
84
84
  from docx._postproc import PostExportOps
85
85
 
86
86
  self._post_export_ops: PostExportOps = PostExportOps()
87
+ # Bumped by ``Document.clear()``. ``Table`` proxies remember the
88
+ # generation they were created in, so a proxy from before a clear
89
+ # can never be re-anchored to a table created after it.
90
+ self._body_generation: int = 0
87
91
 
88
92
  @property
89
93
  def asset_id(self) -> str:
@@ -136,6 +136,10 @@ class Insert(Command):
136
136
  # on the DOCX Studio call (renamed in transit so it doesn't collide with our
137
137
  # discriminator).
138
138
  value_type: str | None = None
139
+ # Text mode only. ``True`` continues the formatting of the run at the
140
+ # insertion point (``Run.add_text``); omitted means the inserted text is
141
+ # a fresh, unformatted run (``Paragraph.add_run``).
142
+ inherit_marks: bool | None = None
139
143
  placement: str | None = None
140
144
  content: dict[str, Any] | None = None
141
145
 
@@ -1543,6 +1547,18 @@ class FindReplace(Command):
1543
1547
  max_replacements: int | None = None
1544
1548
 
1545
1549
 
1550
+ @dataclass
1551
+ class ClearBody(Command):
1552
+ """Replace the whole body story with a single empty paragraph.
1553
+
1554
+ Athena extension backing :meth:`Document.clear`. One server-side
1555
+ write instead of a ``Replace`` per paragraph and per table-cell
1556
+ paragraph; headers, footers and notes are untouched and the final
1557
+ section's page setup survives. Returns ``{nodeId}`` of the new
1558
+ empty paragraph.
1559
+ """
1560
+
1561
+
1546
1562
  @dataclass
1547
1563
  class FindText(Command):
1548
1564
  """Search document text and return bounded match context.
@@ -1576,8 +1592,8 @@ class IterRuns(Command):
1576
1592
 
1577
1593
  # ---------------------------------------------------------------------------
1578
1594
  # PDF Export (Athena extension — python-docx issue #113 keeps getting
1579
- # re-asked despite being closed wontfix. DOCX Studio renders via Daytona
1580
- # (LibreOffice headless) to bytes the client can download or persist.)
1595
+ # re-asked despite being closed wontfix. DOCX Studio renders the document
1596
+ # to bytes the client can download or persist.)
1581
1597
  # ---------------------------------------------------------------------------
1582
1598
 
1583
1599
 
@@ -1759,6 +1775,9 @@ _RESPONSE_BEARING_TYPES: frozenset[str] = frozenset(
1759
1775
  "ExportDocx",
1760
1776
  # FindReplace returns a replacement count for the caller.
1761
1777
  "FindReplace",
1778
+ # ClearBody replaces the whole body; Document.clear awaits it so a
1779
+ # rejected clear raises instead of leaving stale content behind.
1780
+ "ClearBody",
1762
1781
  }
1763
1782
  )
1764
1783
 
@@ -1852,6 +1871,7 @@ for _cls, _issue, _desc in [
1852
1871
  (ContentControlsDelete, "python-docx#155", "SDT delete"),
1853
1872
  (SetSectionColumns, "python-docx#167", "Section multi-column layout"),
1854
1873
  (FindReplace, "python-docx#30", "Formatting-preserving find/replace"),
1874
+ (ClearBody, None, "Document.clear — bulk body reset"),
1855
1875
  (FindText, "python-docx#980", "Fast document text search"),
1856
1876
  (IterRuns, "python-docx#980", "Run stream for run-isolation"),
1857
1877
  (ExportPDF, "python-docx#113", "PDF export"),
@@ -1990,6 +2010,7 @@ __all__ = [
1990
2010
  "ContentControlsDelete",
1991
2011
  "SetSectionColumns",
1992
2012
  "FindReplace",
2013
+ "ClearBody",
1993
2014
  "FindText",
1994
2015
  "IterRuns",
1995
2016
  "ExportPDF",
@@ -965,6 +965,7 @@ class Document:
965
965
  from docx.commands import CreateTOC
966
966
  from docx.toc import TableOfContents
967
967
 
968
+ self._ensure_open()
968
969
  cmd = CreateTOC(
969
970
  at=at or {"kind": "documentEnd"},
970
971
  levels=[levels[0], levels[1]],
@@ -1010,6 +1011,7 @@ class Document:
1010
1011
  from docx.charts import Chart
1011
1012
  from docx.commands import CreateChart
1012
1013
 
1014
+ self._ensure_open()
1013
1015
  cmd = CreateChart(
1014
1016
  chart_type=chart_type,
1015
1017
  data=data,
@@ -1078,6 +1080,7 @@ class Document:
1078
1080
  mime = sniff_content_type(img_bytes, fallback_path=image_path or "")
1079
1081
  kwargs["src"] = f"data:{mime};base64,{base64.b64encode(img_bytes).decode()}"
1080
1082
  cmd = CreateWatermark(**kwargs)
1083
+ self._ensure_open()
1081
1084
  result = run_sync(self._session.send_command(cmd))
1082
1085
  if isinstance(result, dict):
1083
1086
  return str(result.get("id") or result.get("watermarkId") or "")
@@ -1105,6 +1108,7 @@ class Document:
1105
1108
  from docx.commands import CreateContentControl
1106
1109
  from docx.sdt import ContentControl
1107
1110
 
1111
+ self._ensure_open()
1108
1112
  cmd = CreateContentControl(
1109
1113
  control_kind=control_kind,
1110
1114
  at=at or {"kind": "documentEnd"},
@@ -1457,87 +1461,52 @@ class Document:
1457
1461
 
1458
1462
  @athena_extension(
1459
1463
  since="0.14.0",
1460
- description="Document.clear — empty paragraphs + cells so writes start from a clean slate.",
1464
+ description="Document.clear — reset the body to one empty paragraph in a single server write.",
1461
1465
  )
1462
1466
  def clear(self) -> None:
1463
1467
  """Clear the document body so subsequent writes start from a clean slate.
1464
1468
 
1465
- Athena extension — python-docx has no equivalent. Empties every
1466
- top-level paragraph's text content and every table cell's text
1467
- content. The block structure (paragraphs and tables themselves)
1468
- is preserved because DOCX Studio does not yet expose a wire op to
1469
- delete blocks; an agent recovering from a failed run can call
1470
- ``doc.clear()`` then ``doc.add_paragraph(...)`` etc. without
1471
- worrying about stale content concatenating onto its new writes.
1472
-
1473
- Notes / caveats:
1474
- - The post-clear document holds N empty paragraphs (one per
1475
- previously-existing block-level paragraph) plus any empty
1476
- tables. For most agent flows this is invisible because the
1477
- first ``add_paragraph`` / ``add_heading`` extends the doc
1478
- rather than overwriting block positions.
1479
- - To get a TRULY empty body (single empty paragraph, no tables)
1480
- create a fresh asset via ``Document.create()`` instead.
1481
- - This method is best-effort: per-paragraph clear errors are
1482
- swallowed so a partial clear doesn't take down the whole call.
1469
+ Athena extension — python-docx has no equivalent. Replaces the
1470
+ whole body story (paragraphs, headings, tables, images) with a
1471
+ single empty paragraph in one server-side ``ClearBody`` command,
1472
+ so the cost is one round-trip regardless of document size.
1473
+ Headers, footers, footnotes and the final section's page setup
1474
+ are untouched; header/footer references the final section
1475
+ inherited from removed inline sections are kept.
1476
+
1477
+ Export-time rewrites queued against the old body (cell/table
1478
+ formatting, row heights, captured REF paragraphs) are dropped
1479
+ with it, and table numbering restarts from zero, so formatting
1480
+ recorded for a deleted table can never land on one created
1481
+ afterwards at the same position. :class:`~docx.table.Table`
1482
+ proxies obtained before the clear are dead: using one raises
1483
+ :class:`~docx.errors.ValidationError` instead of silently
1484
+ targeting a new table at the same index.
1485
+
1486
+ Raises :class:`~docx.errors.DocxError` if the server rejects the
1487
+ command; the body is never left half-cleared because the whole
1488
+ replacement is applied atomically or not at all, and no local
1489
+ state is touched unless the server accepted it.
1483
1490
  """
1484
- from docx.text.paragraph import Paragraph as _Paragraph
1491
+ from docx.commands import ClearBody
1485
1492
 
1486
1493
  self._ensure_open()
1487
1494
 
1488
- # Clear the list-chain state — the next add_paragraph after
1489
- # clear() should start a new list, not attach to whatever the
1490
- # previous run was doing.
1495
+ run_sync(
1496
+ self._session.send_command(ClearBody()),
1497
+ timeout=LONG_RUNNING_COMMAND_TIMEOUT_SECONDS,
1498
+ )
1499
+
1500
+ self._session._post_export_ops.discard_body_ops()
1501
+ self._table_doc_index_counter = None
1502
+ self._session._table_session_count = 0 # type: ignore[attr-defined]
1503
+ self._session._body_generation += 1
1504
+
1505
+ # The next add_paragraph after clear() should start a new list,
1506
+ # not attach to whatever the previous run was doing.
1491
1507
  self._last_list_item_id = None
1492
1508
  self._last_list_kind = None
1493
1509
 
1494
- for paragraph in self.paragraphs:
1495
- try:
1496
- if not isinstance(paragraph, _Paragraph):
1497
- continue
1498
- if paragraph.text:
1499
- paragraph.clear()
1500
- except Exception as err:
1501
- _log_warn(f"Document.clear: skipped a paragraph: {err!r}")
1502
-
1503
- # Cell clearing must NOT go through ``cell.text = ""``: ``self.tables``
1504
- # materializes fresh ephemeral ``Table`` proxies whose
1505
- # ``_written_cells`` set is empty, so the setter would take the
1506
- # fast (append) path — ``tables.set_cell insideEnd`` with an empty
1507
- # paragraph fragment — which leaves prior cell content untouched.
1508
- # Instead, drive ``doc.replace`` directly against each cell's
1509
- # inner paragraphs (mirroring the clear-then-insert branch in
1510
- # ``_Cell.text``) so the clear semantics don't depend on the
1511
- # in-session write tracking that this code path bypasses.
1512
- from docx.text.paragraph import _node_text
1513
-
1514
- for table in self.tables:
1515
- for row in table.rows:
1516
- for cell in row.cells:
1517
- try:
1518
- existing_pids = cell._inner_paragraph_ids()
1519
- for pid in existing_pids:
1520
- existing_text = _node_text(self._session, pid)
1521
- if not existing_text:
1522
- continue
1523
- run_sync(
1524
- self._session.doc.replace(
1525
- {
1526
- "target": {
1527
- "kind": "text",
1528
- "blockId": pid,
1529
- "range": {
1530
- "start": 0,
1531
- "end": len(existing_text),
1532
- },
1533
- },
1534
- "text": "",
1535
- },
1536
- ),
1537
- )
1538
- except Exception as err:
1539
- _log_warn(f"Document.clear: skipped a cell: {err!r}")
1540
-
1541
1510
  def add_paragraph(
1542
1511
  self,
1543
1512
  text: str = "",