athena-python-docx 0.28.0__tar.gz → 0.29.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 (443) hide show
  1. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/AGENTS.md +113 -36
  2. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_buffer.py +49 -12
  5. athena_python_docx-0.29.0/docx/_capabilities.py +38 -0
  6. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_http_doc.py +239 -26
  7. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_run_order.py +149 -3
  8. athena_python_docx-0.29.0/docx/_tracked.py +29 -0
  9. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/bookmarks.py +13 -9
  10. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/commands.py +72 -16
  11. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/comments.py +131 -44
  12. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/document.py +107 -39
  13. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/shape.py +6 -2
  14. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/errors.py +19 -3
  15. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/fields.py +17 -3
  16. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/sdt.py +19 -0
  17. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/section.py +90 -79
  18. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/shape.py +52 -4
  19. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/table.py +239 -56
  20. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/paragraph.py +118 -12
  21. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/run.py +168 -31
  22. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/pyproject.toml +1 -1
  23. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/ab_probe_cases.py +21 -0
  24. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +1 -0
  25. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/54_empty_everything.json +6 -0
  26. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +2 -0
  27. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +1 -0
  28. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +1 -0
  29. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +1 -0
  30. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +1 -0
  31. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +7 -0
  32. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +15 -0
  33. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +21 -0
  34. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/real_world_cases.py +34 -0
  35. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fixtures/note_reference_reads.json +71 -1
  36. athena_python_docx-0.29.0/tests/fixtures/ruby_reads.json +204 -0
  37. athena_python_docx-0.29.0/tests/fixtures/symbol_reads.json +163 -0
  38. athena_python_docx-0.29.0/tests/live/baseline.json +262 -0
  39. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/reader.py +12 -0
  40. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/runner.py +51 -9
  41. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/test_live_runner.py +28 -0
  42. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/intentional_deviations.json +49 -0
  43. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_batch_chunking.py +166 -0
  44. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_fastpath_runs.py +5 -1
  45. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_paragraphs_listed.py +1 -0
  46. athena_python_docx-0.29.0/tests/test_comment_paragraphs.py +184 -0
  47. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_comments.py +17 -9
  48. athena_python_docx-0.29.0/tests/test_content_control_value.py +75 -0
  49. athena_python_docx-0.29.0/tests/test_empty_hyperlinks.py +91 -0
  50. athena_python_docx-0.29.0/tests/test_export_docx_clean.py +138 -0
  51. athena_python_docx-0.29.0/tests/test_field_refresh.py +32 -0
  52. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_field_runs.py +5 -0
  53. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_http_transport.py +5 -1
  54. athena_python_docx-0.29.0/tests/test_inline_page_break.py +70 -0
  55. athena_python_docx-0.29.0/tests/test_inline_shape_type.py +95 -0
  56. athena_python_docx-0.29.0/tests/test_inline_shapes_floating.py +60 -0
  57. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_note_reference_reads_python_docx_parity.py +9 -5
  58. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_parity_misc.py +2 -2
  59. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_phase_b_headers_footers.py +110 -2
  60. athena_python_docx-0.29.0/tests/test_read_run_ranges.py +153 -0
  61. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_revisions.py +55 -1
  62. athena_python_docx-0.29.0/tests/test_ruby_reads_python_docx_parity.py +192 -0
  63. athena_python_docx-0.29.0/tests/test_run_edges.py +138 -0
  64. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_identity.py +1 -0
  65. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_mark_inheritance.py +88 -42
  66. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_document_audit.py +44 -54
  67. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_header_footer.py +32 -17
  68. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_misc.py +7 -13
  69. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_audit.py +93 -0
  70. athena_python_docx-0.29.0/tests/test_symbol_reads_python_docx_parity.py +122 -0
  71. athena_python_docx-0.29.0/tests/test_table_read_reuse.py +266 -0
  72. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_text_control_characters.py +11 -5
  73. athena_python_docx-0.29.0/tests/test_tracked_revisions_offsets.py +170 -0
  74. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_wire_contract.py +6 -1
  75. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/uv.lock +1 -1
  76. athena_python_docx-0.28.0/tests/fidelity/op_snapshots/54_empty_everything.json +0 -4
  77. athena_python_docx-0.28.0/tests/live/baseline.json +0 -1925
  78. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/.gitignore +0 -0
  79. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/CLAUDE.md +0 -0
  80. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/DOCX_EXEC_LAB.md +0 -0
  81. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/README.md +0 -0
  82. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_athena_extension.py +0 -0
  83. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_batching.py +0 -0
  84. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_citations.py +0 -0
  85. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_execution.py +0 -0
  86. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_http.py +0 -0
  87. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_image_utils.py +0 -0
  88. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_postproc.py +0 -0
  89. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_ptc.py +0 -0
  90. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_references.py +0 -0
  91. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_table_styles.py +0 -0
  92. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/_timeouts.py +0 -0
  93. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/api.py +0 -0
  94. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/blkcntnr.py +0 -0
  95. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/charts.py +0 -0
  96. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/client.py +0 -0
  97. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/drawing/__init__.py +0 -0
  98. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/__init__.py +0 -0
  99. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/base.py +0 -0
  100. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/dml.py +0 -0
  101. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/section.py +0 -0
  102. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/style.py +0 -0
  103. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/table.py +0 -0
  104. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/enum/text.py +0 -0
  105. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/exceptions.py +0 -0
  106. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/footnotes.py +0 -0
  107. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/image/__init__.py +0 -0
  108. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/image/exceptions.py +0 -0
  109. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/image/image.py +0 -0
  110. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/math.py +0 -0
  111. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/opc/__init__.py +0 -0
  112. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/opc/coreprops.py +0 -0
  113. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/oxml/__init__.py +0 -0
  114. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/revisions.py +0 -0
  115. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/session.py +0 -0
  116. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/settings.py +0 -0
  117. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/shared.py +0 -0
  118. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/styles/__init__.py +0 -0
  119. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/styles/_table.py +0 -0
  120. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/styles/latent.py +0 -0
  121. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/styles/style.py +0 -0
  122. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/styles/styles.py +0 -0
  123. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/__init__.py +0 -0
  124. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/font.py +0 -0
  125. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/hyperlink.py +0 -0
  126. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/pagebreak.py +0 -0
  127. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/parfmt.py +0 -0
  128. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/text/tabstops.py +0 -0
  129. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/toc.py +0 -0
  130. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/docx/typing.py +0 -0
  131. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab.py +0 -0
  132. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  133. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  134. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_server.py +0 -0
  135. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/dump_wire_fixtures.py +0 -0
  136. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/release.sh +0 -0
  137. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/round_trip_smoke.py +0 -0
  138. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/smoke_test_block_not_found.py +0 -0
  139. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/scripts/validate_find_replace_asset.py +0 -0
  140. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/__init__.py +0 -0
  141. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/conftest.py +0 -0
  142. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/METHODOLOGY.md +0 -0
  143. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/README.md +0 -0
  144. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/__init__.py +0 -0
  145. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/ab_probe_runner.py +0 -0
  146. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/auto_gen_cases.py +0 -0
  147. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/binary_round_trip.py +0 -0
  148. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/cases.py +0 -0
  149. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/complex_cases.py +0 -0
  150. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/coverage_report.py +0 -0
  151. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/extract.py +0 -0
  152. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/extreme_cases.py +0 -0
  153. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/fake_session.py +0 -0
  154. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/README.md +0 -0
  155. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  156. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  157. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  158. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  159. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  160. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/local_runner.py +0 -0
  161. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/mega_cases.py +0 -0
  162. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshot.py +0 -0
  163. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  164. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  165. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  166. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  167. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  168. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  169. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  170. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  171. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  172. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  173. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  174. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  175. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  176. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  177. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  178. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  179. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  180. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  181. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  182. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  183. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  184. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  185. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  186. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  187. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  188. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  189. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  190. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  191. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  192. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  193. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  194. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  195. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  196. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  197. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  198. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  199. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  200. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  201. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  202. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  203. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  204. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  205. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  206. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  207. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  208. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  209. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  210. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  211. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  212. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  213. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  214. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  215. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  216. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  217. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  218. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  219. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  220. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  221. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  222. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  223. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  224. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  225. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  226. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  227. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  228. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  229. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  230. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  231. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  232. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  233. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  234. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  235. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  236. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  237. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  238. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  239. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  240. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  241. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  242. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  243. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  244. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  245. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  246. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  247. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  248. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  249. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  250. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  251. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  252. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  253. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  254. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  255. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  256. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  257. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  258. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  259. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  260. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  261. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  262. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  263. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  264. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  265. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  266. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  267. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  268. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  269. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  270. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  271. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  272. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  273. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  274. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  275. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  276. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  277. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  278. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  279. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  280. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  281. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  282. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  283. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  284. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  285. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  286. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  287. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  288. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  289. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  290. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  291. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  292. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  293. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  294. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  295. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  296. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  297. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  298. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  299. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  300. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  301. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  302. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/ours_spec.json +0 -0
  303. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/parity_crawl.py +0 -0
  304. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/parity_diff.json +0 -0
  305. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/round_trip_tests.py +0 -0
  306. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/stock_spec.json +0 -0
  307. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  308. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/fixtures/field_reads.json +0 -0
  309. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/__init__.py +0 -0
  310. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/sdk_driver.py +0 -0
  311. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/live/stock_driver.py +0 -0
  312. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/README.md +0 -0
  313. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/__init__.py +0 -0
  314. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/baseline_gaps.json +0 -0
  315. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/compare.py +0 -0
  316. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/introspect.py +0 -0
  317. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  318. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/reports/gap_report.json +0 -0
  319. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/run_parity.py +0 -0
  320. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/snapshots/athena_latest.json +0 -0
  321. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  322. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/parity/test_parity_gap.py +0 -0
  323. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_add_section.py +0 -0
  324. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_add_section_extract_items.py +0 -0
  325. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  326. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_athena_extensions_contract.py +0 -0
  327. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_athena_extensions_registry.py +0 -0
  328. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_batching_perf.py +0 -0
  329. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_block_not_found_error.py +0 -0
  330. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_buffer.py +0 -0
  331. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  332. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_add_table_not_supported.py +0 -0
  333. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_borders_spec.py +0 -0
  334. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  335. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  336. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_format_stash.py +0 -0
  337. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  338. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_run_guard.py +0 -0
  339. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_merge.py +0 -0
  340. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  341. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_cell_text_replace_semantics.py +0 -0
  342. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_citations.py +0 -0
  343. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_collapsed_range_format.py +0 -0
  344. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_color_format_theme.py +0 -0
  345. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_command_dataclasses.py +0 -0
  346. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_commands.py +0 -0
  347. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_core_properties.py +0 -0
  348. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_document_asset_id_property.py +0 -0
  349. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_document_clear.py +0 -0
  350. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_document_create.py +0 -0
  351. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_document_create_from_template.py +0 -0
  352. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_document_factory_validation.py +0 -0
  353. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_docx_exec_lab.py +0 -0
  354. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_docx_exec_lab_server.py +0 -0
  355. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_drawing_image.py +0 -0
  356. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  357. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_enum_parity.py +0 -0
  358. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_execution_scope.py +0 -0
  359. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  360. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_find_replace_session_open.py +0 -0
  361. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_hyperlink_coalescing.py +0 -0
  362. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_image_url_data_uri.py +0 -0
  363. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_inline_shape_alt_text.py +0 -0
  364. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_inline_shape_size.py +0 -0
  365. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_insert_deferred.py +0 -0
  366. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_iter_inner_content.py +0 -0
  367. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_list_styles.py +0 -0
  368. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  369. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_merged_cells.py +0 -0
  370. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_missing_modules.py +0 -0
  371. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_oxml_shim.py +0 -0
  372. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_page_break.py +0 -0
  373. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  374. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_paragraph_text_len_cache.py +0 -0
  375. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_parity_round2.py +0 -0
  376. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_partial_failure_cascade.py +0 -0
  377. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  378. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_phase_a_behavior.py +0 -0
  379. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_phase_c_tables.py +0 -0
  380. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_positional_cell_id.py +0 -0
  381. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  382. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  383. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_postproc_ref_restore.py +0 -0
  384. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_pr19766_review_fixes.py +0 -0
  385. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_ptc.py +0 -0
  386. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_python_docx_api_parity.py +0 -0
  387. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_repeated_node_read.py +0 -0
  388. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_restart_numbering.py +0 -0
  389. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_round_trip_smoke_script.py +0 -0
  390. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_add_picture_anchor.py +0 -0
  391. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_formatting_wire.py +0 -0
  392. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_table_style_objects.py +0 -0
  393. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_text_python_docx.py +0 -0
  394. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  395. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_sdk_reads_served.py +0 -0
  396. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_section_read_lengths.py +0 -0
  397. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  398. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_picture.py +0 -0
  399. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_run.py +0 -0
  400. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  401. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  402. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_comments_get.py +0 -0
  403. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_document_element.py +0 -0
  404. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_enum_section.py +0 -0
  405. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_font_audit.py +0 -0
  406. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_hyperlink.py +0 -0
  407. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_inline_shape.py +0 -0
  408. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  409. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  410. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  411. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  412. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_parfmt.py +0 -0
  413. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  414. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_add_break.py +0 -0
  415. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  416. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_style.py +0 -0
  417. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  418. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_text.py +0 -0
  419. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_underline.py +0 -0
  420. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_audit.py +0 -0
  421. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  422. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_onoff.py +0 -0
  423. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_settings.py +0 -0
  424. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_shared_audit.py +0 -0
  425. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_style.py +0 -0
  426. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_styles.py +0 -0
  427. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_cell.py +0 -0
  428. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  429. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_layout.py +0 -0
  430. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_smoke_integration.py +0 -0
  431. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_acceptance.py +0 -0
  432. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_font.py +0 -0
  433. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_formatting_writes.py +0 -0
  434. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_metadata_writes.py +0 -0
  435. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_names.py +0 -0
  436. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_style_setters_contract.py +0 -0
  437. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_table_set_cell_perf.py +0 -0
  438. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_table_style_id_resolution.py +0 -0
  439. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_temporarily_unavailable.py +0 -0
  440. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_uv_lock_version.py +0 -0
  441. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  442. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_xml_attr_guard.py +0 -0
  443. {athena_python_docx-0.28.0 → athena_python_docx-0.29.0}/tests/test_zod_wire_contract.py +0 -0
@@ -40,12 +40,14 @@ These standard python-docx members don't apply to a DOCX Studio-backed SDK:
40
40
  - `Document.part`, `Paragraph.part`, `Run.part` — package part access
41
41
  - `Document.settings` — Word app settings (not surfaced by DOCX Studio)
42
42
  - `InlineShape.chart` — charts are not currently surfaced by the SDK.
43
- - `Comment.add_paragraph` / `Comment.add_table` /
44
- `Comment.iter_inner_content` / `Comment.paragraphs` /
45
- `Comment.tables` — DOCX Studio models a comment as a single text body.
46
- `Comment` is a `docx.blkcntnr.BlockItemContainer`, as `_Cell` and the
47
- header/footer proxies are, but its paragraph/table-bearing surface raises
48
- `CommentsNotImplementedError`. Use `Comment.text` instead.
43
+ - `Comment.add_table` / `Comment.tables` — a DOCX Studio comment holds
44
+ paragraphs only. `Comment` is a `docx.blkcntnr.BlockItemContainer`, as
45
+ `_Cell` and the header/footer proxies are: `paragraphs`,
46
+ `add_paragraph`, `iter_inner_content` and `text` work as in python-docx
47
+ 1.2.0 (the paragraphs list the comment's story, `blocks.list` with
48
+ `in: {storyType: "comment"}`, and `add_paragraph` sends
49
+ `CommentsParagraphAppend`), while `tables` is empty and `add_table`
50
+ raises `CommentsNotImplementedError`.
49
51
  - **`_Cell.add_table(rows, cols)`** — surface preserved for parity
50
52
  (signature matches python-docx, no `width` kwarg) but raises
51
53
  :class:`docx.errors.NestedTableNotSupportedError` (subclass of
@@ -188,22 +190,33 @@ not file-backed. Each is documented in the relevant docstring.
188
190
  on the other studios: `Workbook.workbook_id` (xlsx) and
189
191
  `Presentation.deck_id` (pptx).
190
192
 
191
- - **`Document.save(path_or_stream=None)`** — argument is optional and,
192
- when supplied, raises
193
- :class:`docx.errors.LocalSaveTargetNotSupportedError`. Stock
194
- python-docx requires it and `TypeError`s on no-arg, but in an
195
- asset-backed SDK there is no local file to write — writes are always
196
- in-place against the Y.Doc. Forcing the upstream signature broke
197
- every agent invocation that reflexively called `doc.save()` (a
198
- near-universal Python pattern), so the no-arg form is supported.
199
- When a path or stream IS supplied, the SDK cannot fulfill the
200
- implied "write bytes to this target" contract, so the call raises
201
- loudly rather than silently flushing — agents must use Olympus's
202
- Export DOCX (which goes through the DOCX Studio session that already
203
- has the bytes) instead of expecting a local file.
204
-
205
- - **`Document.track_revisions: bool`** — when `True`, all subsequent
206
- mutations are recorded as tracked revisions instead of direct edits.
193
+ - **`Document.save(path_or_stream=None)`** — the argument is optional.
194
+ Stock python-docx requires it and `TypeError`s on no-arg, but writes
195
+ are always in place against the Y.Doc, and forcing the upstream
196
+ signature broke every agent invocation that reflexively called
197
+ `doc.save()`, so the no-arg form flushes and writes no file. With a
198
+ path (`str` or `os.PathLike`) or a binary stream, `save` also writes
199
+ the document's `.docx` there, as python-docx does, through
200
+ `export_docx` (0.29.0+; earlier versions raised
201
+ `LocalSaveTargetNotSupportedError`, which stays importable).
202
+
203
+ - **`Document.track_revisions: bool`** — when `True`, subsequent batches
204
+ are sent with `changeMode: "tracked"`, and docx-studio records their text
205
+ edits as Word revisions (`w:ins` / `w:del`): run and paragraph text,
206
+ `find_replace` in the body, new paragraphs and headings (an inserted
207
+ paragraph mark), tabs and line breaks, run formatting (`w:rPrChange`) and
208
+ `paragraph_format` properties (`w:pPrChange`). The replaced text stays, deleted,
209
+ and the new text follows it, so the SDK keeps its paragraph lengths and
210
+ run ranges that way (`docx/_tracked.py`): a tracked `run.text = value`
211
+ 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
215
+ record yet (paragraph styles, tables, pictures, lists, sections, notes,
216
+ page breaks, header/footer/comment text) is refused (HTTP 422,
217
+ `TrackedChangesUnsupported`) and applies nothing; reads, exports,
218
+ comments and `TrackChangesDecide` run either way
219
+ (`DOCX_STUDIO_LIMITATIONS.md` § 32).
207
220
  python-docx upstream has no top-level toggle (the closest is
208
221
  hand-edited `<w:trackChanges/>` on `Document.settings.element`).
209
222
  We expose this as a Document-level property because every DOCX Studio
@@ -219,10 +232,12 @@ not file-backed. Each is documented in the relevant docstring.
219
232
  because the upstream package has no track-changes API at all.
220
233
 
221
234
  - **`Document.user_name: str | None` / `Document.user_email: str |
222
- None`** — author identity threaded through to DOCX Studio on session-
223
- open for tracked-change attribution; DOCX Studio bakes them into the
224
- change records. Separate from `Document.core_properties.last_modified_by`,
225
- the `docProps/core.xml` metadata the SDK reads and writes as python-docx
235
+ 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.
239
+ Separate from `Document.core_properties.last_modified_by`, the
240
+ `docProps/core.xml` metadata the SDK reads and writes as python-docx
226
241
  does.
227
242
 
228
243
  - **`Document.revisions: Revisions`** — collection of tracked changes
@@ -278,9 +293,10 @@ Issue numbers reference `python-openxml/python-docx`.
278
293
  `"FILENAME"`, `"NUMWORDS"`, `"REF"`, `"SEQ"`, `"TOC"`, and the
279
294
  generic `"FIELD"` escape hatch. python-docx has no field API
280
295
  whatsoever; issue #498 (page numbers) and #31 (23 comments) demand
281
- this. `Fields` is sequence-like; `Fields.refresh_all(scope?)`
282
- forces a recompute. Routes through `CreateField` / `FieldsRefresh`
283
- / `FieldsList`.
296
+ this. `Fields` is sequence-like; `Fields.refresh_all(scope?)` updates
297
+ every unlocked REF and SEQ result as Word's F9 does (PAGE, PAGEREF
298
+ and TOC results depend on pages and stay). Routes through
299
+ `CreateField` / `FieldsRefresh` / `FieldsList`.
284
300
 
285
301
  - **`Document.bookmarks: Bookmarks`** + **`Paragraph.add_bookmark
286
302
  (name)`** + **`Document.add_bookmark(name, *, paragraph=None,
@@ -611,12 +627,10 @@ Issue numbers reference `python-openxml/python-docx`.
611
627
 
612
628
  - **`Document.export_docx(path=None, *, include_revisions=False)
613
629
  -> bytes`** (0.11.4+) — export the document's current state as
614
- ``.docx`` bytes, optionally writing to ``path``. Closes the gap
615
- left by ``Document.save(path)`` raising
616
- ``LocalSaveTargetNotSupportedError`` in this SDK: parity test
617
- harnesses and CI workflows need a programmatic .docx export to
618
- diff against ``python-docx`` output that doesn't require a
619
- human-driven Olympus UI action. Routes through ``ExportDocx`` →
630
+ ``.docx`` bytes, optionally writing to ``path``; ``Document.save(path_or_stream)``
631
+ writes its file through it. Parity test harnesses and CI workflows
632
+ use it to diff against ``python-docx`` output without a human-driven
633
+ Olympus UI action. Routes through ``ExportDocx`` →
620
634
  apps/api's backend export path. apps/api
621
635
  writes the session state to a temp ``.docx``, reads bytes back,
622
636
  base64-encodes for the wire, and unlinks the temp in a
@@ -625,6 +639,26 @@ Issue numbers reference `python-openxml/python-docx`.
625
639
  the current backend export path has no ``includeRevisions`` support,
626
640
  so honoring the flag isn't possible yet.
627
641
 
642
+ ``export_docx(path=None, *, include_revisions=False, clean=False,
643
+ clear_title=False)`` (0.29.0+): called with ``clean=True`` it returns a
644
+ clean copy for sending outside the firm instead, from
645
+ ``GET /docs/:id/export.docx?clean=1`` (VIEW gate): docx-studio imports
646
+ the export into an in-memory room, accepts every tracked change and
647
+ deletes every comment through the command runner, exports that room and
648
+ leaves out the author, last-modified-by, revision, company, manager,
649
+ template, editing-time and hyperlink-base properties, rsids, document
650
+ 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
653
+ not changed. The SDK refuses (``DocxUnsupportedCommandError``) an answer
654
+ without ``X-Docx-Clean-Copy: 1``, the plain export an older docx-studio
655
+ sends, and raises ``DocxError`` with docx-studio's reason when a header,
656
+ footer or note still holds a tracked change (the engine accepts the
657
+ body's only; ``DOCX_STUDIO_LIMITATIONS.md`` § 31). The in-process
658
+ post-export rewrites are applied to a clean copy as to a plain export,
659
+ and the copy is refused (``DocxError``) if they put revision, comment or
660
+ rsid markup back into ``word/document.xml``.
661
+
628
662
  Template seeding: ``Document.create()`` (no ``docx=``) already
629
663
  produces an exportable asset because ``POST /docs/empty`` seeds
630
664
  from the default Athena template, so ``export_docx`` works
@@ -915,6 +949,18 @@ architecture or a DOCX Studio constraint:
915
949
  but DOCX Studio's ProseMirror table node can't represent one; the SDK
916
950
  raises eagerly rather than failing opaquely on the wire.
917
951
 
952
+ - **`Document.add_table` writes Athena's brand table.** Owner decision
953
+ (2026-10-12): keep the brand defaults. The table's layout is fixed, so
954
+ `Table.autofit` reads `False` (python-docx leaves autofit on); its columns
955
+ share 9,360 twips, where python-docx shares the section's text width; and
956
+ in the fixed layout a column width the script sets sizes the column's
957
+ cells too, where python-docx sets the `w:gridCol` alone. It also draws
958
+ borders and a zebra fill, which no python-docx read sees. Recorded as
959
+ `live_deviations` for the script cases' `tables.autofit`, `tables.widths`
960
+ and `tables.cell_format` in `tests/parity/intentional_deviations.json`;
961
+ an imported table's gaps stay gaps, and so do the two cases whose
962
+ `cell_format` also differs for another cause (`except`).
963
+
918
964
  - **`_Cell.merge` raises `InvalidSpanError` for every span that would cut
919
965
  through a merged cell.** It merges what python-docx merges and refuses
920
966
  what python-docx refuses (an L- or T-shaped pair of corners), but where
@@ -953,6 +999,18 @@ architecture or a DOCX Studio constraint:
953
999
  Keryx attributes the edit to the signed-in user (and agent), and
954
1000
  nothing reads a comment's author as identity.
955
1001
 
1002
+ - **A comment's paragraphs are in Word's comment style, which the export
1003
+ defines.** python-docx 1.2.0's `add_comment` and `Comment.add_paragraph`
1004
+ write `w:pStyle CommentText` (Word's built-in "annotation text", Comment
1005
+ Text in Word's UI) without defining the style in `styles.xml`, so
1006
+ python-docx reads those paragraphs as Normal. docx-studio writes the same
1007
+ `w:pStyle` and defines the style as Word does: `Comment.paragraphs[i].style`
1008
+ reads `Comment Text` (a built-in the document lacks reads back as that
1009
+ built-in, as above), and the export adds Word's definition of the style and
1010
+ of its linked `Comment Text Char` to `styles.xml`, so python-docx reads the
1011
+ exported paragraph as `annotation text`. Owner decision, 2026-10-12.
1012
+ Recorded in `tests/parity/intentional_deviations.json` (`live_deviations`).
1013
+
956
1014
  - **`ParagraphFormat.line_spacing_rule = None` warns-and-preserves on a
957
1015
  clear** rather than raising (upstream accepts `None` to clear, but DOCX
958
1016
  Studio's merging mutation ops have no single-attribute clear). It emits a
@@ -970,7 +1028,17 @@ architecture or a DOCX Studio constraint:
970
1028
  given. `Run.add_tab()` and `Run.add_break()` take the run's formatting, as
971
1029
  upstream appends them to the run's `w:r`; `Run.add_break(WD_BREAK.COLUMN)`
972
1030
  sends a column break (`breakType: "column"`), which docx-studio writes after
973
- the paragraph's content. `DOCX_STUDIO_LIMITATIONS.md` §26.
1031
+ the paragraph's content. `DOCX_STUDIO_LIMITATIONS.md` §26. `Run.text` and
1032
+ `Paragraph.text` leave a ruby's base text out (`w:ruby`, a phonetic guide
1033
+ over its base text), as upstream reads only a run's own text elements, while
1034
+ the base text keeps its room in the text-address space (`ruby` spans on the
1035
+ read's run; `tests/test_ruby_reads_python_docx_parity.py`). That holds while
1036
+ the paragraph's runs are as its records hold them, in the body, a table cell,
1037
+ a header, a footer or a comment; a paragraph with a link or a tracked change
1038
+ reads its runs from their marks, the base text included. A write to the run
1039
+ (its text, an append, its formatting) makes the base text ordinary text,
1040
+ which then reads as text: docx-studio keeps no guide through an edit, where
1041
+ upstream keeps the `w:ruby` through all but a text write.
974
1042
 
975
1043
  - **`CoreProperties.modified` is the time of the last save.** The asset is a
976
1044
  live Word document, and docx-studio stamps `dcterms:modified` when it saves
@@ -1104,6 +1172,15 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
1104
1172
  the context-manager exit drain explicitly; `docx.flush_all()` is
1105
1173
  the executor-postamble hook that flushes every live buffer in the
1106
1174
  process.
1175
+ - A flush of more than 500 commands (`MAX_BATCH_COMMANDS`,
1176
+ docx-studio's request cap) goes out as consecutive requests, and
1177
+ docx-studio applies each all or nothing: when one fails, the requests
1178
+ before it are saved and it and every later one are not. The
1179
+ `DocxError` (0.29.0+) says how many of the flush's commands were
1180
+ applied and names the failed one by its flush index; it carries
1181
+ `unapplied_commands` and `failed_command`, and `partial_applied`
1182
+ holds the saved requests' results. A retry re-applies the unapplied
1183
+ edits, never the whole flush.
1107
1184
  - Execution scope: executor sandboxes may keep Python globals
1108
1185
  between tool calls so imports, constants, and helper functions can be
1109
1186
  reused. Live SDK objects are different. The executor calls
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.28.0
3
+ Version: 0.29.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.28.0"
9
+ __version__ = "0.29.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -43,7 +43,13 @@ from docx._execution import (
43
43
  is_stale_execution,
44
44
  )
45
45
  from docx._timeouts import timeout_for_commands
46
- from docx.commands import Command, GetNodeById, is_response_bearing, must_flush_immediately
46
+ from docx.commands import (
47
+ Command,
48
+ GetNodeById,
49
+ is_query,
50
+ is_response_bearing,
51
+ must_flush_immediately,
52
+ )
47
53
  from docx.errors import DocxError, DocxUnsupportedCommandError, FlushAllError
48
54
 
49
55
 
@@ -402,6 +408,11 @@ class CommandBuffer:
402
408
  # The last command's ``GetNodeById`` key, result and time, while
403
409
  # nothing has been sent or buffered after it (see :meth:`call`).
404
410
  self._last_read: tuple[str, Any, float] | None = None
411
+ # Counts each command that may change the document (anything but a
412
+ # query) this buffer has taken, buffered or sent, and each
413
+ # forget_reads(): a read kept from an earlier count (a ``Table``'s
414
+ # ``tables.get``) may no longer show the document. See ``writes``.
415
+ self._writes: int = 0
405
416
  _register(self)
406
417
 
407
418
  def register_proxy_id_ref(self, client_id: str, proxy: object, attr: str = "_node_id") -> None:
@@ -460,10 +471,15 @@ class CommandBuffer:
460
471
  if current == mode:
461
472
  return
462
473
  # Drain any queued commands with the *previous* mode before
463
- # adopting the new one.
464
- self.flush()
465
- with self._lock:
466
- self._change_mode = mode
474
+ # adopting the new one. The new mode is adopted even when that
475
+ # flush raises (docx-studio refuses a tracked batch that edits):
476
+ # ``Document`` has already recorded the new flag, so keeping the
477
+ # old mode here would refuse every later direct edit.
478
+ try:
479
+ self.flush()
480
+ finally:
481
+ with self._lock:
482
+ self._change_mode = mode
467
483
 
468
484
  def set_user(self, name: str | None, email: str | None = None) -> None:
469
485
  """Set the batch-level user identity.
@@ -485,11 +501,34 @@ class CommandBuffer:
485
501
  if email:
486
502
  self._user["email"] = email
487
503
 
504
+ @property
505
+ def writes(self) -> int:
506
+ """How many commands that may change the document this buffer has
507
+ taken, buffered or sent, plus each :meth:`forget_reads` (which a batch
508
+ another handle of the document sends calls). A read kept at one count
509
+ shows the document while the count stays, but for a collaborator's
510
+ edit."""
511
+ with self._lock:
512
+ return self._writes
513
+
488
514
  def forget_reads(self) -> None:
489
515
  """The next node read goes to the server, not to the read before it
490
- (:meth:`call`): for a read that checks the document before a write."""
516
+ (:meth:`call`), and so does a table's next read (``writes``): for a
517
+ read that checks the document before a write."""
491
518
  with self._lock:
492
519
  self._last_read = None
520
+ self._writes += 1
521
+
522
+ def ensure_usable(self) -> None:
523
+ """Raise as :meth:`call` does before it sends or reuses anything: for a
524
+ buffer of an earlier execution, a batch the idle timer failed to send,
525
+ and a closed buffer. A read kept outside the buffer checks it too."""
526
+ self._assert_current_execution()
527
+ self._raise_deferred_flush_error()
528
+ if self._closed:
529
+ raise RuntimeError(
530
+ f"CommandBuffer for {self._asset_id} is closed",
531
+ )
493
532
 
494
533
  def call(self, cmd: Command) -> Any:
495
534
  """Execute or buffer ``cmd``.
@@ -508,12 +547,7 @@ class CommandBuffer:
508
547
  ``clientIdMap`` on flush and the buffer rewrites each registered
509
548
  proxy's ``_node_id`` in-place.
510
549
  """
511
- self._assert_current_execution()
512
- self._raise_deferred_flush_error()
513
- if self._closed:
514
- raise RuntimeError(
515
- f"CommandBuffer for {self._asset_id} is closed",
516
- )
550
+ self.ensure_usable()
517
551
 
518
552
  # A read of the node the last command read, with nothing sent or
519
553
  # buffered since and within READ_REUSE_SECONDS of it, answers from
@@ -532,6 +566,9 @@ class CommandBuffer:
532
566
  and _now() - last_read[2] <= READ_REUSE_SECONDS
533
567
  ):
534
568
  return copy.deepcopy(last_read[1])
569
+ if not is_query(cmd):
570
+ with self._lock:
571
+ self._writes += 1
535
572
 
536
573
  # PTC begin: emit only for commands in the allow-list. Other
537
574
  # commands still flow through the buffer (and through the batched
@@ -0,0 +1,38 @@
1
+ """What the docx-studio a session talks to takes, from its ``Info`` reply.
2
+
3
+ A command shape an older docx-studio would refuse (``InsertLineBreak`` with
4
+ ``breakType: "page"``) is sent only to a server that names it in
5
+ ``Info.capabilities``; a server that names none gets the older shape. The
6
+ promotion rings put tenants on different docx-studio trains, so an SDK release
7
+ meets servers from before and after the capability.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import weakref
13
+ from typing import Any
14
+
15
+ from docx._batching import run_sync
16
+
17
+ # Session -> the capabilities its server reported, read once.
18
+ _capabilities: "weakref.WeakKeyDictionary[Any, dict[str, Any]]" = weakref.WeakKeyDictionary()
19
+
20
+
21
+ def server_takes(session: Any, capability: str) -> bool:
22
+ """True when the session's docx-studio reports ``capability``
23
+ (``Info.capabilities``), read on first use and kept for the session.
24
+
25
+ ``Info`` flushes the edits queued before it, as every read does.
26
+ """
27
+ if session is None:
28
+ return False
29
+ try:
30
+ known = _capabilities.get(session)
31
+ except TypeError:
32
+ return False
33
+ if known is None:
34
+ info: object = run_sync(session.doc.info({}))
35
+ reported = info.get("capabilities") if isinstance(info, dict) else None
36
+ known = reported if isinstance(reported, dict) else {}
37
+ _capabilities[session] = known
38
+ return known.get(capability) is True