athena-python-docx 0.27.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 (444) hide show
  1. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/.gitignore +2 -0
  2. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/AGENTS.md +178 -49
  3. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/PKG-INFO +1 -1
  4. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/__init__.py +1 -1
  5. athena_python_docx-0.29.0/docx/_batching.py +137 -0
  6. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_buffer.py +122 -12
  7. athena_python_docx-0.29.0/docx/_capabilities.py +38 -0
  8. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_http_doc.py +347 -22
  9. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_run_order.py +149 -3
  10. athena_python_docx-0.29.0/docx/_tracked.py +29 -0
  11. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/bookmarks.py +13 -9
  12. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/client.py +7 -0
  13. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/commands.py +72 -16
  14. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/comments.py +131 -44
  15. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/document.py +107 -39
  16. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/shape.py +6 -2
  17. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/errors.py +19 -3
  18. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/fields.py +17 -3
  19. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/sdt.py +19 -0
  20. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/section.py +90 -79
  21. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/shape.py +52 -4
  22. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/table.py +239 -56
  23. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/hyperlink.py +4 -4
  24. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/paragraph.py +130 -16
  25. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/run.py +179 -30
  26. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/pyproject.toml +1 -1
  27. athena_python_docx-0.29.0/scripts/round_trip_smoke.py +426 -0
  28. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/METHODOLOGY.md +49 -1
  29. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/ab_probe_cases.py +21 -0
  30. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +1 -0
  31. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/54_empty_everything.json +6 -0
  32. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +2 -0
  33. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +1 -0
  34. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +1 -0
  35. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +1 -0
  36. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +1 -0
  37. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +7 -0
  38. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +15 -0
  39. athena_python_docx-0.29.0/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +21 -0
  40. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/real_world_cases.py +34 -0
  41. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fixtures/field_reads.json +160 -1
  42. athena_python_docx-0.29.0/tests/fixtures/note_reference_reads.json +263 -0
  43. athena_python_docx-0.29.0/tests/fixtures/ruby_reads.json +204 -0
  44. athena_python_docx-0.29.0/tests/fixtures/symbol_reads.json +163 -0
  45. athena_python_docx-0.29.0/tests/live/__init__.py +0 -0
  46. athena_python_docx-0.29.0/tests/live/baseline.json +262 -0
  47. athena_python_docx-0.29.0/tests/live/reader.py +243 -0
  48. athena_python_docx-0.29.0/tests/live/runner.py +742 -0
  49. athena_python_docx-0.29.0/tests/live/sdk_driver.py +56 -0
  50. athena_python_docx-0.29.0/tests/live/stock_driver.py +65 -0
  51. athena_python_docx-0.29.0/tests/live/test_live_runner.py +439 -0
  52. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/intentional_deviations.json +88 -0
  53. athena_python_docx-0.29.0/tests/test_batch_chunking.py +379 -0
  54. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_fastpath_runs.py +5 -1
  55. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_paragraphs_listed.py +1 -0
  56. athena_python_docx-0.29.0/tests/test_comment_paragraphs.py +184 -0
  57. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_comments.py +17 -9
  58. athena_python_docx-0.29.0/tests/test_content_control_value.py +75 -0
  59. athena_python_docx-0.29.0/tests/test_empty_hyperlinks.py +91 -0
  60. athena_python_docx-0.29.0/tests/test_export_docx_clean.py +138 -0
  61. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_field_reads_python_docx_parity.py +6 -1
  62. athena_python_docx-0.29.0/tests/test_field_refresh.py +32 -0
  63. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_field_runs.py +21 -3
  64. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_http_transport.py +5 -1
  65. athena_python_docx-0.29.0/tests/test_inline_page_break.py +70 -0
  66. athena_python_docx-0.29.0/tests/test_inline_shape_type.py +95 -0
  67. athena_python_docx-0.29.0/tests/test_inline_shapes_floating.py +60 -0
  68. athena_python_docx-0.29.0/tests/test_note_reference_reads_python_docx_parity.py +240 -0
  69. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_parity_misc.py +2 -2
  70. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_phase_b_headers_footers.py +110 -2
  71. athena_python_docx-0.29.0/tests/test_read_run_ranges.py +153 -0
  72. athena_python_docx-0.29.0/tests/test_repeated_node_read.py +119 -0
  73. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_revisions.py +55 -1
  74. athena_python_docx-0.29.0/tests/test_round_trip_smoke_script.py +115 -0
  75. athena_python_docx-0.29.0/tests/test_ruby_reads_python_docx_parity.py +192 -0
  76. athena_python_docx-0.29.0/tests/test_run_edges.py +138 -0
  77. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_identity.py +1 -0
  78. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_mark_inheritance.py +88 -42
  79. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_document_audit.py +44 -54
  80. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_header_footer.py +32 -17
  81. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_misc.py +7 -13
  82. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_audit.py +93 -0
  83. athena_python_docx-0.29.0/tests/test_symbol_reads_python_docx_parity.py +122 -0
  84. athena_python_docx-0.29.0/tests/test_table_read_reuse.py +266 -0
  85. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_text_control_characters.py +11 -5
  86. athena_python_docx-0.29.0/tests/test_tracked_revisions_offsets.py +170 -0
  87. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_wire_contract.py +6 -1
  88. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/uv.lock +1 -1
  89. athena_python_docx-0.27.0/docx/_batching.py +0 -88
  90. athena_python_docx-0.27.0/scripts/round_trip_smoke.py +0 -231
  91. athena_python_docx-0.27.0/tests/fidelity/op_snapshots/54_empty_everything.json +0 -4
  92. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/CLAUDE.md +0 -0
  93. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/DOCX_EXEC_LAB.md +0 -0
  94. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/README.md +0 -0
  95. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_athena_extension.py +0 -0
  96. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_citations.py +0 -0
  97. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_execution.py +0 -0
  98. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_http.py +0 -0
  99. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_image_utils.py +0 -0
  100. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_postproc.py +0 -0
  101. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_ptc.py +0 -0
  102. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_references.py +0 -0
  103. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_table_styles.py +0 -0
  104. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/_timeouts.py +0 -0
  105. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/api.py +0 -0
  106. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/blkcntnr.py +0 -0
  107. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/charts.py +0 -0
  108. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/drawing/__init__.py +0 -0
  109. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/__init__.py +0 -0
  110. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/base.py +0 -0
  111. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/dml.py +0 -0
  112. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/section.py +0 -0
  113. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/style.py +0 -0
  114. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/table.py +0 -0
  115. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/enum/text.py +0 -0
  116. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/exceptions.py +0 -0
  117. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/footnotes.py +0 -0
  118. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/image/__init__.py +0 -0
  119. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/image/exceptions.py +0 -0
  120. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/image/image.py +0 -0
  121. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/math.py +0 -0
  122. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/opc/__init__.py +0 -0
  123. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/opc/coreprops.py +0 -0
  124. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/oxml/__init__.py +0 -0
  125. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/revisions.py +0 -0
  126. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/session.py +0 -0
  127. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/settings.py +0 -0
  128. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/shared.py +0 -0
  129. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/styles/__init__.py +0 -0
  130. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/styles/_table.py +0 -0
  131. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/styles/latent.py +0 -0
  132. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/styles/style.py +0 -0
  133. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/styles/styles.py +0 -0
  134. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/__init__.py +0 -0
  135. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/font.py +0 -0
  136. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/pagebreak.py +0 -0
  137. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/parfmt.py +0 -0
  138. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/text/tabstops.py +0 -0
  139. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/toc.py +0 -0
  140. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/docx/typing.py +0 -0
  141. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab.py +0 -0
  142. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  143. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  144. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/docx_exec_lab_server.py +0 -0
  145. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/dump_wire_fixtures.py +0 -0
  146. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/release.sh +0 -0
  147. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/smoke_test_block_not_found.py +0 -0
  148. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/scripts/validate_find_replace_asset.py +0 -0
  149. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/__init__.py +0 -0
  150. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/conftest.py +0 -0
  151. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/README.md +0 -0
  152. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/__init__.py +0 -0
  153. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/ab_probe_runner.py +0 -0
  154. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/auto_gen_cases.py +0 -0
  155. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/binary_round_trip.py +0 -0
  156. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/cases.py +0 -0
  157. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/complex_cases.py +0 -0
  158. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/coverage_report.py +0 -0
  159. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/extract.py +0 -0
  160. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/extreme_cases.py +0 -0
  161. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/fake_session.py +0 -0
  162. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/README.md +0 -0
  163. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  164. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  165. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  166. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  167. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  168. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/local_runner.py +0 -0
  169. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/mega_cases.py +0 -0
  170. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshot.py +0 -0
  171. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  172. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  173. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  174. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  175. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  176. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  177. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  178. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  179. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  180. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  181. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  182. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  183. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  184. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  185. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  186. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  187. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  188. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  189. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  190. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  191. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  192. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  193. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  194. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  195. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  196. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  197. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  198. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  199. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  200. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  201. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  202. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  203. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  204. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  205. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  206. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  207. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  208. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  209. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  210. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  211. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  212. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  213. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  214. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  215. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  216. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  217. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  218. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  219. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  220. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  221. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  222. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  223. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  224. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  225. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  226. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  227. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  228. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  229. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  230. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  231. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  232. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  233. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  234. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  235. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  236. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  237. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  238. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  239. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  240. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  241. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  242. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  243. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  244. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  245. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  246. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  247. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  248. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  249. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  250. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  251. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  252. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  253. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  254. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  255. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  256. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  257. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  258. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  259. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  260. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  261. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  262. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  263. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  264. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  265. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  266. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  267. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  268. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  269. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  270. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  271. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  272. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  273. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  274. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  275. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  276. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  277. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  278. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  279. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  280. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  281. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  282. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  283. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  284. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  285. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  286. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  287. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  288. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  289. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  290. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  291. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  292. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  293. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  294. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  295. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  296. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  297. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  298. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  299. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  300. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  301. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  302. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  303. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  304. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  305. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  306. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  307. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  308. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  309. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  310. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/ours_spec.json +0 -0
  311. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/parity_crawl.py +0 -0
  312. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/parity_diff.json +0 -0
  313. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/round_trip_tests.py +0 -0
  314. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/stock_spec.json +0 -0
  315. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  316. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/README.md +0 -0
  317. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/__init__.py +0 -0
  318. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/baseline_gaps.json +0 -0
  319. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/compare.py +0 -0
  320. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/introspect.py +0 -0
  321. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  322. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/reports/gap_report.json +0 -0
  323. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/run_parity.py +0 -0
  324. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/snapshots/athena_latest.json +0 -0
  325. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  326. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/parity/test_parity_gap.py +0 -0
  327. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_add_section.py +0 -0
  328. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_add_section_extract_items.py +0 -0
  329. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  330. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_athena_extensions_contract.py +0 -0
  331. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_athena_extensions_registry.py +0 -0
  332. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_batching_perf.py +0 -0
  333. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_block_not_found_error.py +0 -0
  334. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_buffer.py +0 -0
  335. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  336. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_add_table_not_supported.py +0 -0
  337. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_borders_spec.py +0 -0
  338. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  339. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  340. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_format_stash.py +0 -0
  341. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  342. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_inner_run_guard.py +0 -0
  343. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_merge.py +0 -0
  344. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  345. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_cell_text_replace_semantics.py +0 -0
  346. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_citations.py +0 -0
  347. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_collapsed_range_format.py +0 -0
  348. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_color_format_theme.py +0 -0
  349. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_command_dataclasses.py +0 -0
  350. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_commands.py +0 -0
  351. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_core_properties.py +0 -0
  352. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_document_asset_id_property.py +0 -0
  353. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_document_clear.py +0 -0
  354. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_document_create.py +0 -0
  355. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_document_create_from_template.py +0 -0
  356. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_document_factory_validation.py +0 -0
  357. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_docx_exec_lab.py +0 -0
  358. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_docx_exec_lab_server.py +0 -0
  359. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_drawing_image.py +0 -0
  360. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  361. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_enum_parity.py +0 -0
  362. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_execution_scope.py +0 -0
  363. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_find_replace_session_open.py +0 -0
  364. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_hyperlink_coalescing.py +0 -0
  365. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_image_url_data_uri.py +0 -0
  366. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_inline_shape_alt_text.py +0 -0
  367. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_inline_shape_size.py +0 -0
  368. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_insert_deferred.py +0 -0
  369. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_iter_inner_content.py +0 -0
  370. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_list_styles.py +0 -0
  371. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  372. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_merged_cells.py +0 -0
  373. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_missing_modules.py +0 -0
  374. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_oxml_shim.py +0 -0
  375. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_page_break.py +0 -0
  376. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  377. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_paragraph_text_len_cache.py +0 -0
  378. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_parity_round2.py +0 -0
  379. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_partial_failure_cascade.py +0 -0
  380. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  381. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_phase_a_behavior.py +0 -0
  382. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_phase_c_tables.py +0 -0
  383. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_positional_cell_id.py +0 -0
  384. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  385. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  386. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_postproc_ref_restore.py +0 -0
  387. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_pr19766_review_fixes.py +0 -0
  388. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_ptc.py +0 -0
  389. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_python_docx_api_parity.py +0 -0
  390. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_restart_numbering.py +0 -0
  391. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_add_picture_anchor.py +0 -0
  392. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_formatting_wire.py +0 -0
  393. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_table_style_objects.py +0 -0
  394. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_text_python_docx.py +0 -0
  395. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  396. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_sdk_reads_served.py +0 -0
  397. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_section_read_lengths.py +0 -0
  398. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  399. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_picture.py +0 -0
  400. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_add_run.py +0 -0
  401. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  402. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  403. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_comments_get.py +0 -0
  404. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_document_element.py +0 -0
  405. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_enum_section.py +0 -0
  406. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_font_audit.py +0 -0
  407. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_hyperlink.py +0 -0
  408. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_inline_shape.py +0 -0
  409. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  410. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  411. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  412. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  413. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_parfmt.py +0 -0
  414. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  415. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_add_break.py +0 -0
  416. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  417. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_style.py +0 -0
  418. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  419. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_text.py +0 -0
  420. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_run_underline.py +0 -0
  421. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_audit.py +0 -0
  422. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  423. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_section_onoff.py +0 -0
  424. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_settings.py +0 -0
  425. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_shared_audit.py +0 -0
  426. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_style.py +0 -0
  427. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_styles.py +0 -0
  428. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_cell.py +0 -0
  429. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  430. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_silent_stub_table_layout.py +0 -0
  431. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_smoke_integration.py +0 -0
  432. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_acceptance.py +0 -0
  433. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_font.py +0 -0
  434. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_formatting_writes.py +0 -0
  435. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_metadata_writes.py +0 -0
  436. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_names.py +0 -0
  437. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_style_setters_contract.py +0 -0
  438. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_table_set_cell_perf.py +0 -0
  439. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_table_style_id_resolution.py +0 -0
  440. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_temporarily_unavailable.py +0 -0
  441. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_uv_lock_version.py +0 -0
  442. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  443. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_xml_attr_guard.py +0 -0
  444. {athena_python_docx-0.27.0 → athena_python_docx-0.29.0}/tests/test_zod_wire_contract.py +0 -0
@@ -18,6 +18,8 @@ dist/
18
18
  .pytest_cache/
19
19
  .mypy_cache/
20
20
  .ruff_cache/
21
+ # The live parity runner's scoreboard and exports (python-sdk/tests/live/runner.py).
22
+ /python-sdk/out/
21
23
 
22
24
  # Editors
23
25
  .vscode/
@@ -25,6 +25,13 @@ Before adding or modifying any API surface:
25
25
 
26
26
  Run `uv run pytest tests/test_python_docx_api_parity.py -v -s` to verify parity.
27
27
 
28
+ The API ratchet sees shape only. For behaviour, `uv run --extra dev python -m
29
+ tests.live.runner --cases <name>` runs a battery case through stock
30
+ python-docx 1.2.0 and through the SDK against a live in-memory DOCX Studio
31
+ and compares what each reads, field by field (`tests/fidelity/METHODOLOGY.md`
32
+ § L9). CI fails on a live gap `tests/live/baseline.json` does not hold, and
33
+ on a baseline gap that is gone.
34
+
28
35
  ### Intentionally omitted (current SDK limitations)
29
36
 
30
37
  These standard python-docx members don't apply to a DOCX Studio-backed SDK:
@@ -33,12 +40,14 @@ These standard python-docx members don't apply to a DOCX Studio-backed SDK:
33
40
  - `Document.part`, `Paragraph.part`, `Run.part` — package part access
34
41
  - `Document.settings` — Word app settings (not surfaced by DOCX Studio)
35
42
  - `InlineShape.chart` — charts are not currently surfaced by the SDK.
36
- - `Comment.add_paragraph` / `Comment.add_table` /
37
- `Comment.iter_inner_content` / `Comment.paragraphs` /
38
- `Comment.tables` — DOCX Studio models a comment as a single text body.
39
- `Comment` is a `docx.blkcntnr.BlockItemContainer`, as `_Cell` and the
40
- header/footer proxies are, but its paragraph/table-bearing surface raises
41
- `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`.
42
51
  - **`_Cell.add_table(rows, cols)`** — surface preserved for parity
43
52
  (signature matches python-docx, no `width` kwarg) but raises
44
53
  :class:`docx.errors.NestedTableNotSupportedError` (subclass of
@@ -181,22 +190,33 @@ not file-backed. Each is documented in the relevant docstring.
181
190
  on the other studios: `Workbook.workbook_id` (xlsx) and
182
191
  `Presentation.deck_id` (pptx).
183
192
 
184
- - **`Document.save(path_or_stream=None)`** — argument is optional and,
185
- when supplied, raises
186
- :class:`docx.errors.LocalSaveTargetNotSupportedError`. Stock
187
- python-docx requires it and `TypeError`s on no-arg, but in an
188
- asset-backed SDK there is no local file to write — writes are always
189
- in-place against the Y.Doc. Forcing the upstream signature broke
190
- every agent invocation that reflexively called `doc.save()` (a
191
- near-universal Python pattern), so the no-arg form is supported.
192
- When a path or stream IS supplied, the SDK cannot fulfill the
193
- implied "write bytes to this target" contract, so the call raises
194
- loudly rather than silently flushing — agents must use Olympus's
195
- Export DOCX (which goes through the DOCX Studio session that already
196
- has the bytes) instead of expecting a local file.
197
-
198
- - **`Document.track_revisions: bool`** — when `True`, all subsequent
199
- 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).
200
220
  python-docx upstream has no top-level toggle (the closest is
201
221
  hand-edited `<w:trackChanges/>` on `Document.settings.element`).
202
222
  We expose this as a Document-level property because every DOCX Studio
@@ -212,10 +232,12 @@ not file-backed. Each is documented in the relevant docstring.
212
232
  because the upstream package has no track-changes API at all.
213
233
 
214
234
  - **`Document.user_name: str | None` / `Document.user_email: str |
215
- None`** — author identity threaded through to DOCX Studio on session-
216
- open for tracked-change attribution; DOCX Studio bakes them into the
217
- change records. Separate from `Document.core_properties.last_modified_by`,
218
- 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
219
241
  does.
220
242
 
221
243
  - **`Document.revisions: Revisions`** — collection of tracked changes
@@ -271,9 +293,10 @@ Issue numbers reference `python-openxml/python-docx`.
271
293
  `"FILENAME"`, `"NUMWORDS"`, `"REF"`, `"SEQ"`, `"TOC"`, and the
272
294
  generic `"FIELD"` escape hatch. python-docx has no field API
273
295
  whatsoever; issue #498 (page numbers) and #31 (23 comments) demand
274
- this. `Fields` is sequence-like; `Fields.refresh_all(scope?)`
275
- forces a recompute. Routes through `CreateField` / `FieldsRefresh`
276
- / `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`.
277
300
 
278
301
  - **`Document.bookmarks: Bookmarks`** + **`Paragraph.add_bookmark
279
302
  (name)`** + **`Document.add_bookmark(name, *, paragraph=None,
@@ -291,7 +314,9 @@ Issue numbers reference `python-openxml/python-docx`.
291
314
  `FootnotesGet` / `FootnotesPatch` / `FootnotesDelete`. The
292
315
  parallel **`Document.endnotes: Endnotes`** + **`Run.add_endnote
293
316
  (text, *, custom_mark=None)`** mirrors the same machinery for
294
- end-of-section notes.
317
+ end-of-section notes. Both list the notes a reference reaches, as
318
+ Word and the export do: a note whose reference was deleted in the
319
+ editor stays in the package for undo, and is not listed.
295
320
 
296
321
  - **`Document.add_toc(*, levels=(1, 3), style_id=None,
297
322
  include_hyperlinks=True, title=None, tab_leader="dot", at=None)
@@ -418,6 +443,8 @@ Issue numbers reference `python-openxml/python-docx`.
418
443
  inspection. Use this when an agent needs to sample or inspect runs
419
444
  without issuing one ``getNodeById`` query per paragraph through
420
445
  ``doc.paragraphs`` + ``paragraph.runs``. Routes through `IterRuns`.
446
+ These three see a footnote or endnote only while a reference reaches
447
+ it, as `Document.footnotes` / `Document.endnotes` list them.
421
448
 
422
449
  - **`Paragraph.list_id` / `Paragraph.list_level` /
423
450
  `Paragraph.list_format` / `Paragraph.list_number`** — list-item
@@ -600,12 +627,10 @@ Issue numbers reference `python-openxml/python-docx`.
600
627
 
601
628
  - **`Document.export_docx(path=None, *, include_revisions=False)
602
629
  -> bytes`** (0.11.4+) — export the document's current state as
603
- ``.docx`` bytes, optionally writing to ``path``. Closes the gap
604
- left by ``Document.save(path)`` raising
605
- ``LocalSaveTargetNotSupportedError`` in this SDK: parity test
606
- harnesses and CI workflows need a programmatic .docx export to
607
- diff against ``python-docx`` output that doesn't require a
608
- 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`` →
609
634
  apps/api's backend export path. apps/api
610
635
  writes the session state to a temp ``.docx``, reads bytes back,
611
636
  base64-encodes for the wire, and unlinks the temp in a
@@ -614,6 +639,26 @@ Issue numbers reference `python-openxml/python-docx`.
614
639
  the current backend export path has no ``includeRevisions`` support,
615
640
  so honoring the flag isn't possible yet.
616
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
+
617
662
  Template seeding: ``Document.create()`` (no ``docx=``) already
618
663
  produces an exportable asset because ``POST /docs/empty`` seeds
619
664
  from the default Athena template, so ``export_docx`` works
@@ -904,6 +949,18 @@ architecture or a DOCX Studio constraint:
904
949
  but DOCX Studio's ProseMirror table node can't represent one; the SDK
905
950
  raises eagerly rather than failing opaquely on the wire.
906
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
+
907
964
  - **`_Cell.merge` raises `InvalidSpanError` for every span that would cut
908
965
  through a merged cell.** It merges what python-docx merges and refuses
909
966
  what python-docx refuses (an L- or T-shaped pair of corners), but where
@@ -942,6 +999,18 @@ architecture or a DOCX Studio constraint:
942
999
  Keryx attributes the edit to the signed-in user (and agent), and
943
1000
  nothing reads a comment's author as identity.
944
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
+
945
1014
  - **`ParagraphFormat.line_spacing_rule = None` warns-and-preserves on a
946
1015
  clear** rather than raising (upstream accepts `None` to clear, but DOCX
947
1016
  Studio's merging mutation ops have no single-attribute clear). It emits a
@@ -959,7 +1028,24 @@ architecture or a DOCX Studio constraint:
959
1028
  given. `Run.add_tab()` and `Run.add_break()` take the run's formatting, as
960
1029
  upstream appends them to the run's `w:r`; `Run.add_break(WD_BREAK.COLUMN)`
961
1030
  sends a column break (`breakType: "column"`), which docx-studio writes after
962
- 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.
1042
+
1043
+ - **`CoreProperties.modified` is the time of the last save.** The asset is a
1044
+ live Word document, and docx-studio stamps `dcterms:modified` when it saves
1045
+ a change to the package: a section, style or property write, and the export
1046
+ of a changed document. Word stamps it on every save; upstream leaves the
1047
+ value it read until the script sets it. Owner decision, 2026-10-12. Recorded
1048
+ in `tests/parity/intentional_deviations.json` (`live_deviations`).
963
1049
 
964
1050
  - **Tracked changes read as Word's final view.** `Paragraph.text`, `runs`,
965
1051
  `iter_inner_content()`, `Hyperlink.text` / `runs` and `_Cell.text` include
@@ -973,23 +1059,45 @@ architecture or a DOCX Studio constraint:
973
1059
  Markup) show insertions and hide deletions, as these reads do.
974
1060
  `doc.revisions` lists every change (`tests/test_run_text_python_docx.py`).
975
1061
 
1062
+ - **A citation link Athena added reads as its text, as the export writes it**
1063
+ (owner decision #40122). Athena's citation flow stamps the links it writes
1064
+ with the `Athena citation` tooltip. These links only navigate inside Athena,
1065
+ so the export leaves them out and keeps their text: no `w:hyperlink`, and no
1066
+ citation highlight on that text.
1067
+ - **The reads match the export.** The run reads with no `hyperlink` and no
1068
+ highlight in `Paragraph.runs`, `Paragraph.hyperlinks`, a cell's paragraphs
1069
+ and docx-studio's markdown read.
1070
+ - **Where upstream differs.** Upstream reads the room's `w:hyperlink` as a
1071
+ link.
1072
+ - **Which links are Athena's** is decided by the room's provenance, not by
1073
+ the tooltip alone. A link with the tooltip that came in the uploaded file
1074
+ (the room's source package holds it) is a link everywhere, as Word keeps
1075
+ it.
1076
+ - **Tests:** `applier.test.ts` › `applier — citations`.
1077
+
976
1078
  - **A field's runs read as python-docx reads them; some writes to them
977
1079
  differ.** `Paragraph.text` includes a complex field's displayed result and
978
1080
  `Paragraph.runs` holds its begin, field code, separate, result and end runs
979
1081
  (each with its own formatting), as python-docx reads the `w:r` children of
980
- a `w:p`; a simple field (`w:fldSimple`) reads as nothing, and a field in a
981
- link is the link's, as in python-docx. Each paragraph of a field that spans
1082
+ a `w:p`; a simple field (`w:fldSimple`) reads as nothing (one in a tracked
1083
+ change, which the export writes as a complex field, reads that field's
1084
+ runs), a result run of a note reference reads `""`, and a field in a link
1085
+ is the link's, as in python-docx. Each paragraph of a field that spans
982
1086
  paragraphs (a table of contents) holds the field character runs it has
983
1087
  (`tests/test_field_reads_python_docx_parity.py`, against stock python-docx
984
1088
  on the same `.docx`; `DOCX_STUDIO_LIMITATIONS.md` § 27). A field takes no
985
1089
  room in the text-address space, so its runs stand at one offset. Writes:
986
1090
  - setting a result run's `.text` changes the field's displayed result,
987
- as in python-docx (`Replace` with a `field` target), but the export
988
- writes a changed result of several runs as one run, in the first run's
989
- formatting, and a result run read before the field's result changed
990
- (through another read's run, or by a collaborator) raises
991
- `FieldRunWriteError` rather than write over that change, where
992
- python-docx's run is live;
1091
+ as in python-docx (`Replace` with a `field` target): the export keeps
1092
+ the result's runs where the new text allows (text still there stays in
1093
+ its run, new text goes in the run whose text it replaced; another result
1094
+ run's tab or Word character stays as the source wrote it, and a note
1095
+ reference stays where it is, where python-docx's write of its run would
1096
+ delete it), but writes no result run left with no text, where
1097
+ python-docx keeps an empty `w:r`, and a result run read before the
1098
+ field's result changed (through another read's run, or by a
1099
+ collaborator) raises `FieldRunWriteError` rather than write over that
1100
+ change, where python-docx's run is live;
993
1101
  - formatting a result run formats the field's whole result (`FormatApply`
994
1102
  with a `field` target), from its source formatting, where python-docx
995
1103
  formats that run alone;
@@ -1006,10 +1114,22 @@ architecture or a DOCX Studio constraint:
1006
1114
  `add_footnote`, `add_endnote`, `add_math` and `add_cross_reference` on
1007
1115
  any of a field's runs raise `FieldRunWriteError`; python-docx appends to
1008
1116
  that `w:r`.
1009
- A field that `Run.add_field` adds is a simple field, so it reads as no
1010
- runs and no text, though docx-studio's export writes it as a complex field.
1011
- Against a docx-studio that predates `fieldRun` reads, a field reads as no
1012
- runs and no text, as before (`tests/test_field_runs.py`).
1117
+ A field that `Run.add_field` adds is a complex field, as Word's Insert
1118
+ Field writes one, so its paragraph reads its runs, as python-docx reads the
1119
+ exported file. Against a docx-studio that predates `fieldRun` reads, a
1120
+ field reads as no runs and no text, as before (`tests/test_field_runs.py`).
1121
+
1122
+ - **`Font.name = "…"` also clears the theme fonts of the two slots it
1123
+ sets.** python-docx writes the name to `w:rFonts`' `w:ascii` and `w:hAnsi`
1124
+ and leaves a `w:asciiTheme` / `w:hAnsiTheme` beside them; Word reads a
1125
+ theme font over the name in its slot (ISO/IEC 29500-1 §17.3.2.26), so
1126
+ after python-docx's write Word still shows the theme font. The SDK sets the
1127
+ same two slots and docx-studio drops their theme fonts with them, so Word
1128
+ shows the font that was set. The run's other slots (`w:eastAsia`, `w:cs`
1129
+ and their theme fonts) and its `w:hint` stay as they were, as in
1130
+ python-docx. The export writes exactly the slots the run's fonts hold
1131
+ (#42248). Recorded in `tests/parity/intentional_deviations.json`
1132
+ (`_comment_behavioral_deviations`).
1013
1133
 
1014
1134
  ### If you need a deviation
1015
1135
 
@@ -1052,6 +1172,15 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
1052
1172
  the context-manager exit drain explicitly; `docx.flush_all()` is
1053
1173
  the executor-postamble hook that flushes every live buffer in the
1054
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.
1055
1184
  - Execution scope: executor sandboxes may keep Python globals
1056
1185
  between tool calls so imports, constants, and helper functions can be
1057
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.27.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.27.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
@@ -0,0 +1,137 @@
1
+ """Sync→async bridge. Runs a single event loop in a background thread
2
+ and dispatches coroutines from sync callers.
3
+
4
+ This is the only place in the SDK that uses threading.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import concurrent.futures
11
+ import contextvars
12
+ import threading
13
+ from typing import Any, Coroutine, TypeVar
14
+
15
+ from docx._timeouts import DEFAULT_OP_TIMEOUT_SECONDS
16
+ from docx.errors import OperationTimeoutError
17
+
18
+ T = TypeVar("T")
19
+
20
+ _loop: asyncio.AbstractEventLoop | None = None
21
+ _thread: threading.Thread | None = None
22
+ _lock = threading.Lock()
23
+
24
+
25
+ class _Progress:
26
+ """What the thread waiting on a call (:func:`run_sync`) and the call share:
27
+ the steps the call has finished, and whether the waiter gave up."""
28
+
29
+ __slots__ = ("abandoned", "steps")
30
+
31
+ def __init__(self) -> None:
32
+ self.steps = 0
33
+ self.abandoned = False
34
+
35
+
36
+ _progress: contextvars.ContextVar[_Progress | None] = contextvars.ContextVar(
37
+ "docx_sdk_call_progress", default=None
38
+ )
39
+
40
+
41
+ def note_progress() -> None:
42
+ """A step of the running call finished: one batch of a flush that goes
43
+ out in several (``HttpClient.execute_batch``). :func:`run_sync` gives the
44
+ call its ``timeout`` again, so each batch has the budget its request has."""
45
+ progress = _progress.get()
46
+ if progress is not None:
47
+ progress.steps += 1
48
+
49
+
50
+ def call_abandoned() -> bool:
51
+ """True once the caller of the running call timed out
52
+ (:class:`OperationTimeoutError`): a call of several steps starts no more."""
53
+ progress = _progress.get()
54
+ return progress is not None and progress.abandoned
55
+
56
+
57
+ def _ensure_loop() -> asyncio.AbstractEventLoop:
58
+ """Return the persistent background event loop. Starts it lazily."""
59
+ global _loop, _thread
60
+
61
+ with _lock:
62
+ if _loop is not None and _loop.is_running():
63
+ return _loop
64
+
65
+ loop = asyncio.new_event_loop()
66
+ loop_ready = threading.Event()
67
+
68
+ def _run() -> None:
69
+ asyncio.set_event_loop(loop)
70
+ loop_ready.set()
71
+ loop.run_forever()
72
+
73
+ thread = threading.Thread(
74
+ target=_run,
75
+ name="docx-sdk-loop",
76
+ daemon=True,
77
+ )
78
+ thread.start()
79
+ loop_ready.wait(timeout=5)
80
+ _loop = loop
81
+ _thread = thread
82
+ return loop
83
+
84
+
85
+ def run_sync(
86
+ coro: Coroutine[Any, Any, T],
87
+ *,
88
+ timeout: float | None = DEFAULT_OP_TIMEOUT_SECONDS,
89
+ ) -> T:
90
+ """Run a coroutine on the background loop and block until it returns.
91
+
92
+ Args:
93
+ coro: The coroutine to execute.
94
+ timeout: Maximum seconds to wait, counted again whenever the call
95
+ finishes a step (:func:`note_progress`). ``None`` blocks
96
+ indefinitely (use sparingly — prefer the default so stalls
97
+ surface early).
98
+
99
+ Raises:
100
+ OperationTimeoutError: if the coroutine neither completes nor
101
+ finishes a step within `timeout` seconds. The call then starts
102
+ no further step (:func:`call_abandoned`).
103
+ The coroutine's exception, re-raised in the calling thread.
104
+ """
105
+ loop = _ensure_loop()
106
+ progress = _Progress()
107
+ # The call runs in a copy of this thread's context (call_soon_threadsafe
108
+ # and the task each copy the current one), so it finds `progress`.
109
+ token = _progress.set(progress)
110
+ try:
111
+ future = asyncio.run_coroutine_threadsafe(coro, loop)
112
+ finally:
113
+ _progress.reset(token)
114
+ seen = 0
115
+ while True:
116
+ try:
117
+ return future.result(timeout=timeout)
118
+ except concurrent.futures.TimeoutError as exc:
119
+ if progress.steps > seen:
120
+ seen = progress.steps
121
+ continue
122
+ progress.abandoned = True
123
+ future.cancel()
124
+ raise OperationTimeoutError(timeout_seconds=timeout) from exc
125
+
126
+
127
+ def shutdown() -> None:
128
+ """Stop the background event loop. For test teardown."""
129
+ global _loop, _thread
130
+ with _lock:
131
+ if _loop is None:
132
+ return
133
+ _loop.call_soon_threadsafe(_loop.stop)
134
+ if _thread is not None:
135
+ _thread.join(timeout=5)
136
+ _loop = None
137
+ _thread = None