athena-python-docx 0.15.2__tar.gz → 0.15.3__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 (359) hide show
  1. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/CLAUDE.md +7 -0
  2. athena_python_docx-0.15.3/DOCX_EXEC_LAB.md +189 -0
  3. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/PKG-INFO +10 -1
  4. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/README.md +9 -0
  5. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/__init__.py +2 -3
  6. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_batching.py +1 -7
  7. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_buffer.py +40 -6
  8. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_http_doc.py +11 -16
  9. athena_python_docx-0.15.3/docx/_timeouts.py +32 -0
  10. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/client.py +16 -0
  11. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/commands.py +25 -3
  12. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/document.py +93 -11
  13. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/errors.py +15 -6
  14. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/pyproject.toml +1 -1
  15. athena_python_docx-0.15.3/scripts/docx_exec_lab.py +509 -0
  16. athena_python_docx-0.15.3/scripts/docx_exec_lab_examples/fast_table_fill.py +28 -0
  17. athena_python_docx-0.15.3/scripts/docx_exec_lab_examples/find_replace_literal.py +16 -0
  18. athena_python_docx-0.15.3/scripts/docx_exec_lab_server.py +1030 -0
  19. athena_python_docx-0.15.3/scripts/validate_find_replace_asset.py +237 -0
  20. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/52_iterate_everything.json +1 -1
  21. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +1 -1
  22. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/91_many_small_tables.json +1 -1
  23. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_athena_extensions_contract.py +18 -2
  24. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_athena_extensions_registry.py +4 -9
  25. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_buffer.py +146 -0
  26. athena_python_docx-0.15.3/tests/test_docx_exec_lab.py +178 -0
  27. athena_python_docx-0.15.3/tests/test_docx_exec_lab_server.py +106 -0
  28. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_execution_scope.py +2 -1
  29. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_find_replace_session_open.py +111 -0
  30. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_http_transport.py +60 -0
  31. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_iter_inner_content.py +36 -0
  32. athena_python_docx-0.15.3/tests/test_validate_find_replace_asset_script.py +109 -0
  33. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_wire_contract.py +12 -2
  34. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/uv.lock +1 -1
  35. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/.gitignore +0 -0
  36. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_athena_extension.py +0 -0
  37. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_execution.py +0 -0
  38. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_http.py +0 -0
  39. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_image_utils.py +0 -0
  40. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_postproc.py +0 -0
  41. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_ptc.py +0 -0
  42. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/_table_styles.py +0 -0
  43. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/api.py +0 -0
  44. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/bookmarks.py +0 -0
  45. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/charts.py +0 -0
  46. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/comments.py +0 -0
  47. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/enum/__init__.py +0 -0
  48. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/enum/section.py +0 -0
  49. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/enum/style.py +0 -0
  50. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/enum/table.py +0 -0
  51. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/enum/text.py +0 -0
  52. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/exceptions.py +0 -0
  53. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/fields.py +0 -0
  54. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/footnotes.py +0 -0
  55. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/math.py +0 -0
  56. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/opc/__init__.py +0 -0
  57. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/opc/coreprops.py +0 -0
  58. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/oxml/__init__.py +0 -0
  59. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/revisions.py +0 -0
  60. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/sdt.py +0 -0
  61. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/section.py +0 -0
  62. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/session.py +0 -0
  63. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/settings.py +0 -0
  64. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/shape.py +0 -0
  65. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/shared.py +0 -0
  66. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/styles/__init__.py +0 -0
  67. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/styles/style.py +0 -0
  68. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/styles/styles.py +0 -0
  69. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/table.py +0 -0
  70. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/__init__.py +0 -0
  71. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/font.py +0 -0
  72. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/hyperlink.py +0 -0
  73. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/pagebreak.py +0 -0
  74. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/paragraph.py +0 -0
  75. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/parfmt.py +0 -0
  76. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/run.py +0 -0
  77. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/text/tabstops.py +0 -0
  78. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/toc.py +0 -0
  79. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/docx/typing.py +0 -0
  80. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/scripts/publish.sh +0 -0
  81. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/scripts/release.sh +0 -0
  82. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/scripts/round_trip_smoke.py +0 -0
  83. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/scripts/smoke_test_block_not_found.py +0 -0
  84. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/__init__.py +0 -0
  85. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/conftest.py +0 -0
  86. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/METHODOLOGY.md +0 -0
  87. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/README.md +0 -0
  88. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/__init__.py +0 -0
  89. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/ab_probe_cases.py +0 -0
  90. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/ab_probe_runner.py +0 -0
  91. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/auto_gen_cases.py +0 -0
  92. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/binary_round_trip.py +0 -0
  93. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/cases.py +0 -0
  94. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/complex_cases.py +0 -0
  95. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/coverage_report.py +0 -0
  96. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/extract.py +0 -0
  97. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/extreme_cases.py +0 -0
  98. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/fake_session.py +0 -0
  99. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/README.md +0 -0
  100. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/__init__.py +0 -0
  101. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/_runner.py +0 -0
  102. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/extractor.py +0 -0
  103. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  104. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  105. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/local_runner.py +0 -0
  106. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/mega_cases.py +0 -0
  107. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshot.py +0 -0
  108. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  109. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  110. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  111. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  112. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  113. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  114. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  115. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  116. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  117. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  118. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  119. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  120. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  121. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  122. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  123. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  124. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  125. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  126. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  127. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  128. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  129. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  130. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  131. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  132. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  133. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  134. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  135. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  136. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  137. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  138. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  139. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  140. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  141. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  142. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  143. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  144. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  145. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  146. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  147. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  148. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  149. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  150. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  151. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  152. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  153. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  154. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  155. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  156. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  157. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  158. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  159. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  160. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  161. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  162. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  163. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  164. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  165. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  166. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  167. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  168. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  169. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  170. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  171. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  172. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  173. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  174. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  175. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  176. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  177. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  178. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  179. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  180. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  181. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  182. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  183. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  184. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  185. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  186. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  187. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  188. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  189. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  190. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  191. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  192. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  193. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  194. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  195. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  196. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  197. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  198. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  199. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  200. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  201. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  202. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  203. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  204. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  205. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  206. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  207. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  208. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  209. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  210. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  211. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  212. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  213. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  214. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  215. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  216. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  217. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  218. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  219. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  220. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  221. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  222. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  223. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  224. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  225. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  226. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  227. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  228. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  229. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  230. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  231. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  232. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  233. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  234. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  235. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  236. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  237. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  238. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  239. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  240. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  241. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  242. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  243. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  244. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  245. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  246. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  247. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  248. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  249. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  250. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  251. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  252. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/ours_spec.json +0 -0
  253. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/parity_crawl.py +0 -0
  254. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/parity_diff.json +0 -0
  255. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/real_world_cases.py +0 -0
  256. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/round_trip_tests.py +0 -0
  257. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/runner.py +0 -0
  258. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/stock_spec.json +0 -0
  259. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/fidelity/test_e2e_against_staging.py +0 -0
  260. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/README.md +0 -0
  261. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/__init__.py +0 -0
  262. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/baseline_gaps.json +0 -0
  263. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/compare.py +0 -0
  264. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/intentional_deviations.json +0 -0
  265. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/introspect.py +0 -0
  266. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  267. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/reports/gap_report.json +0 -0
  268. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/run_parity.py +0 -0
  269. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/snapshots/athena_latest.json +0 -0
  270. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  271. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/parity/test_parity_gap.py +0 -0
  272. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_add_section_extract_items.py +0 -0
  273. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_batching_perf.py +0 -0
  274. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_block_not_found_error.py +0 -0
  275. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  276. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_add_table_not_supported.py +0 -0
  277. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  278. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  279. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_inner_format_stash.py +0 -0
  280. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_inner_run_format_stash.py +0 -0
  281. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_inner_run_guard.py +0 -0
  282. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_text_plain_fastpath.py +0 -0
  283. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_cell_text_replace_semantics.py +0 -0
  284. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_collapsed_range_format.py +0 -0
  285. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_command_dataclasses.py +0 -0
  286. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_commands.py +0 -0
  287. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_comments.py +0 -0
  288. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_document_asset_id_property.py +0 -0
  289. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_document_clear.py +0 -0
  290. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_document_create.py +0 -0
  291. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_document_create_from_template.py +0 -0
  292. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_document_factory_validation.py +0 -0
  293. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_e2e_partial_failure_cascade.py +0 -0
  294. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_hyperlink_coalescing.py +0 -0
  295. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_insert_deferred.py +0 -0
  296. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_list_styles.py +0 -0
  297. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_merged_cell_secondary_slot.py +0 -0
  298. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_merged_cells.py +0 -0
  299. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_oxml_shim.py +0 -0
  300. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_paragraph_text_len_cache.py +0 -0
  301. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_parity_misc.py +0 -0
  302. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_parity_round2.py +0 -0
  303. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_partial_failure_cascade.py +0 -0
  304. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_phase_a_behavior.py +0 -0
  305. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_phase_b_headers_footers.py +0 -0
  306. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_phase_c_tables.py +0 -0
  307. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_postproc_cell_format_rewrite.py +0 -0
  308. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  309. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_postproc_ref_restore.py +0 -0
  310. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_pr19766_review_fixes.py +0 -0
  311. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_ptc.py +0 -0
  312. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_python_docx_api_parity.py +0 -0
  313. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_revisions.py +0 -0
  314. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  315. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_add_picture.py +0 -0
  316. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_add_run.py +0 -0
  317. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  318. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_comments_add_comment.py +0 -0
  319. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_comments_get.py +0 -0
  320. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_document_audit.py +0 -0
  321. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_document_element.py +0 -0
  322. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_enum_section.py +0 -0
  323. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_font_audit.py +0 -0
  324. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_header_footer.py +0 -0
  325. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_hyperlink.py +0 -0
  326. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_inline_shape.py +0 -0
  327. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  328. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_misc.py +0 -0
  329. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_paragraph_strict.py +0 -0
  330. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_paragraph_style.py +0 -0
  331. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  332. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_parfmt.py +0 -0
  333. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_row_col_cell.py +0 -0
  334. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_add_break.py +0 -0
  335. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_bool_setters.py +0 -0
  336. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_style.py +0 -0
  337. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_style_strict.py +0 -0
  338. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_text.py +0 -0
  339. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_run_underline.py +0 -0
  340. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_section_audit.py +0 -0
  341. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_section_dimensions.py +0 -0
  342. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_section_onoff.py +0 -0
  343. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_settings.py +0 -0
  344. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_shared_audit.py +0 -0
  345. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_style.py +0 -0
  346. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_styles.py +0 -0
  347. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_table_audit.py +0 -0
  348. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_table_cell.py +0 -0
  349. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_table_dimensions.py +0 -0
  350. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_silent_stub_table_layout.py +0 -0
  351. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_smoke_integration.py +0 -0
  352. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_style_acceptance.py +0 -0
  353. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_style_font.py +0 -0
  354. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_style_setters_contract.py +0 -0
  355. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_table_set_cell_perf.py +0 -0
  356. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_table_style_id_resolution.py +0 -0
  357. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_temporarily_unavailable.py +0 -0
  358. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_xml_attr_guard.py +0 -0
  359. {athena_python_docx-0.15.2 → athena_python_docx-0.15.3}/tests/test_zod_wire_contract.py +0 -0
@@ -338,6 +338,13 @@ Issue numbers reference `python-openxml/python-docx`.
338
338
  `"endnotes"` / `"comments"` / `"all"`. Routes through
339
339
  `FindReplace`.
340
340
 
341
+ - **`Document.find_text(pattern, *, regex=False, match_case=False,
342
+ whole_word=False, in_=None, max_results=20, context_chars=80)
343
+ -> dict`** — fast bounded text search for large-doc inspection.
344
+ Returns `{count, matches, truncated}` with context snippets instead
345
+ of exporting the whole `.docx` or walking every paragraph/run through
346
+ live SDK reads. Routes through `FindText`.
347
+
341
348
  - **`Document.iter_runs(*, in_=None, limit=None, offset=None)
342
349
  -> list[dict]`** — server-side run enumeration for large-doc
343
350
  inspection. Use this when an agent needs to sample or inspect runs
@@ -0,0 +1,189 @@
1
+ # DocX Execution Lab
2
+
3
+ `scripts/docx_exec_lab.py` is a headless runner for quickly testing
4
+ `athena-python-docx` snippets against Athena SuperDocument assets. It
5
+ shortens the debug loop by running local SDK code directly against a
6
+ chosen DOCX Studio API, capturing stdout/stderr/errors/timings, and
7
+ optionally exporting the result to `.docx` for assertions.
8
+
9
+ Use this before waiting on a full Agent -> Daytona -> preview cycle when
10
+ debugging SDK behavior such as large-document replacement, table fills,
11
+ unsupported OOXML internals, or export fidelity.
12
+
13
+ ## Inputs
14
+
15
+ The runner accepts code from `--code-file` or stdin. It injects:
16
+
17
+ - `ATHENA_DOCX_ASSET_ID` - the asset id passed with `--asset-id`
18
+ - `ATHENA_DOCX_BASE_URL` and `DOCX_STUDIO_BASE_URL` - when `--base-url` is set
19
+ - `DOCX_EXEC_LAB_OUTPUT_DIR` - output folder for the run
20
+ - `DOCX_EXEC_LAB_EXPORT_PATH` - export target when `--export-docx` is set
21
+
22
+ Authentication is read from the normal SDK environment, usually:
23
+
24
+ ```bash
25
+ export ATHENA_DOCX_API_KEY="<your-api-key>"
26
+ ```
27
+
28
+ Do not commit API keys. Use shell env vars or your local secret manager.
29
+
30
+ ## Run Against A PR Preview
31
+
32
+ ```bash
33
+ cd docx-studio/python-sdk
34
+
35
+ export ATHENA_DOCX_API_KEY="<your-api-key>"
36
+
37
+ uv run python scripts/docx_exec_lab.py \
38
+ --base-url "https://docx-studio-pr21665-preview.previews.athenaintel.com" \
39
+ --asset-id "asset_..." \
40
+ --code-file scripts/docx_exec_lab_examples/find_replace_literal.py \
41
+ --timeout 30 \
42
+ --output-dir /tmp/docx-lab-find-replace \
43
+ --export-docx \
44
+ --assert-stdout-contains "Replacements made:" \
45
+ --assert-docx-text-contains "[Purchaser]"
46
+ ```
47
+
48
+ The script writes structured JSON to `<output-dir>/result.json` and
49
+ prints the same JSON to stdout. The JSON includes success flags,
50
+ duration, stdout, stderr, exit code, error text, code path, asset id, and
51
+ artifact paths.
52
+
53
+ ## Run Against Staging
54
+
55
+ ```bash
56
+ cd docx-studio/python-sdk
57
+
58
+ export ATHENA_DOCX_API_KEY="<your-staging-api-key>"
59
+ export ATHENA_DOCX_BASE_URL="https://docx-studio.stg.athenaintel.com"
60
+
61
+ uv run python scripts/docx_exec_lab.py \
62
+ --asset-id "asset_..." \
63
+ --code-file scripts/docx_exec_lab_examples/fast_table_fill.py \
64
+ --timeout 30 \
65
+ --output-dir /tmp/docx-lab-table-fill \
66
+ --export-docx \
67
+ --assert-stdout-contains "Filled 4 table rows" \
68
+ --assert-docx-text-contains "LOW (NYSE)"
69
+ ```
70
+
71
+ ## Run Against Local DOCX Studio
72
+
73
+ Start DOCX Studio locally, then point the runner at that base URL:
74
+
75
+ ```bash
76
+ cd docx-studio/python-sdk
77
+
78
+ export ATHENA_DOCX_API_KEY="<local-or-dev-api-key>"
79
+
80
+ uv run python scripts/docx_exec_lab.py \
81
+ --base-url "http://localhost:3001" \
82
+ --asset-id "asset_..." \
83
+ --code-file scripts/docx_exec_lab_examples/find_replace_literal.py \
84
+ --output-dir /tmp/docx-lab-local \
85
+ --export-docx
86
+ ```
87
+
88
+ ## Local UI With SuperDoc Embed
89
+
90
+ The lab also includes a local-only HTML UI that wraps the same headless
91
+ runner and iframes Olympus's existing SuperDoc embed route.
92
+
93
+ ```bash
94
+ cd docx-studio/python-sdk
95
+
96
+ export ATHENA_DOCX_API_KEY="<your-staging-api-key>"
97
+
98
+ uv run python scripts/docx_exec_lab_server.py --open
99
+ ```
100
+
101
+ Defaults:
102
+
103
+ - DOCX Studio API: `https://docx-studio.stg.athenaintel.com`
104
+ - Agora embed-token API: `https://agora-staging.athenaintel.com`
105
+ - Olympus iframe host: `https://staging-app.athenaintel.com`
106
+
107
+ The UI accepts an `asset_id`, Python code, and optional assertions. The
108
+ right pane can mint an editable embed token through staging Agora and
109
+ iframe the returned `https://staging-app.athenaintel.com/embed/{token}`
110
+ URL, so changes render in the real Olympus/SuperDoc viewer.
111
+
112
+ If the staging Agora URL differs, pass:
113
+
114
+ ```bash
115
+ uv run python scripts/docx_exec_lab_server.py \
116
+ --agora-base-url "https://..." \
117
+ --olympus-base-url "https://staging-app.athenaintel.com" \
118
+ --docx-base-url "https://docx-studio.stg.athenaintel.com"
119
+ ```
120
+
121
+ The page also has an API key field. Values entered there are sent only
122
+ to the local server for that request and are not written to `result.json`.
123
+
124
+ ## Use Stdin For One-Off Repros
125
+
126
+ ```bash
127
+ cd docx-studio/python-sdk
128
+
129
+ printf '%s\n' \
130
+ 'import os' \
131
+ 'from docx import Document' \
132
+ 'doc = Document(os.environ["ATHENA_DOCX_ASSET_ID"])' \
133
+ 'print(doc.asset_id)' \
134
+ | uv run python scripts/docx_exec_lab.py \
135
+ --asset-id "asset_..." \
136
+ --base-url "https://docx-studio-pr21665-preview.previews.athenaintel.com" \
137
+ --assert-stdout-contains "asset_"
138
+ ```
139
+
140
+ ## Export Assertions
141
+
142
+ When `--export-docx` is set, the snippet must leave an open global
143
+ variable named `doc`. The lab calls:
144
+
145
+ ```python
146
+ doc.export_docx("<output-dir>/exported.docx")
147
+ ```
148
+
149
+ Then `--assert-docx-text-contains` extracts text from the exported Word
150
+ XML and checks for expected content. This catches "the command returned
151
+ success but the document did not change" failures.
152
+
153
+ If a snippet needs custom export behavior, pass `--export-path` without
154
+ `--export-docx` and write `os.environ["DOCX_EXEC_LAB_EXPORT_PATH"]`
155
+ inside the snippet. The lab records that file if it exists.
156
+
157
+ ## Table Fill Guidance
158
+
159
+ Use the fast cell text path for bulk table values:
160
+
161
+ ```python
162
+ table = doc.add_table(rows=len(rows), cols=2, style="Table Grid")
163
+ for row_index, (label, value) in enumerate(rows):
164
+ table.cell(row_index, 0).text = label
165
+ table.cell(row_index, 1).text = value
166
+ doc.save()
167
+ ```
168
+
169
+ Avoid reading `cell.paragraphs[0].runs[0]` inside the fill loop. That
170
+ interleaves writes with remote reads, flushes pending operations, and is
171
+ much slower on real assets.
172
+
173
+ ## Opt-In Real Asset Smoke
174
+
175
+ The unit tests do not require network access. A real export smoke is
176
+ available but skipped unless explicitly enabled:
177
+
178
+ ```bash
179
+ cd docx-studio/python-sdk
180
+
181
+ export ATHENA_DOCX_LAB_RUN_INTEGRATION=1
182
+ export ATHENA_DOCX_LAB_ASSET_ID="asset_..."
183
+ export ATHENA_DOCX_API_KEY="<your-api-key>"
184
+ export ATHENA_DOCX_BASE_URL="https://docx-studio-pr21665-preview.previews.athenaintel.com"
185
+
186
+ uv run pytest tests/test_docx_exec_lab.py -m integration -q
187
+ ```
188
+
189
+ Use disposable or test assets for mutation snippets.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-docx
3
- Version: 0.15.2
3
+ Version: 0.15.3
4
4
  Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
5
5
  Project-URL: Homepage, https://athenaintelligence.ai
6
6
  Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
@@ -67,6 +67,15 @@ uv pip install -e ".[dev]"
67
67
  uv run pytest tests/ -x
68
68
  ```
69
69
 
70
+ ## DocX Execution Lab
71
+
72
+ For fast local repros against real Athena document assets, use the
73
+ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
74
+ Python snippet with this checkout of `athena-python-docx`, captures
75
+ stdout/stderr/errors/timings, and can export the resulting `.docx` for
76
+ text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
77
+ an Olympus/SuperDoc embed preview pane. See `DOCX_EXEC_LAB.md`.
78
+
70
79
  ## Environment variables
71
80
 
72
81
  Required when connecting to Keryx (set by Athena backend when executing in Daytona):
@@ -40,6 +40,15 @@ uv pip install -e ".[dev]"
40
40
  uv run pytest tests/ -x
41
41
  ```
42
42
 
43
+ ## DocX Execution Lab
44
+
45
+ For fast local repros against real Athena document assets, use the
46
+ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
47
+ Python snippet with this checkout of `athena-python-docx`, captures
48
+ stdout/stderr/errors/timings, and can export the resulting `.docx` for
49
+ text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
50
+ an Olympus/SuperDoc embed preview pane. See `DOCX_EXEC_LAB.md`.
51
+
43
52
  ## Environment variables
44
53
 
45
54
  Required when connecting to Keryx (set by Athena backend when executing in Daytona):
@@ -6,11 +6,11 @@ See CLAUDE.md for the API parity contract.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- __version__ = "0.15.2"
9
+ __version__ = "0.15.3"
10
10
 
11
- from docx._execution import begin_execution
12
11
  from docx.api import Document
13
12
  from docx._buffer import flush_all
13
+
14
14
  # Re-exports python-docx ships at docx top-level for convenience.
15
15
  from docx.shared import Emu, Inches, Pt, Cm, Mm, Twips, Length, RGBColor
16
16
 
@@ -24,7 +24,6 @@ __all__ = [
24
24
  "Twips",
25
25
  "Length",
26
26
  "RGBColor",
27
- "begin_execution",
28
27
  "flush_all",
29
28
  "__version__",
30
29
  ]
@@ -11,17 +11,11 @@ import concurrent.futures
11
11
  import threading
12
12
  from typing import Any, Coroutine, TypeVar
13
13
 
14
+ from docx._timeouts import DEFAULT_OP_TIMEOUT_SECONDS
14
15
  from docx.errors import OperationTimeoutError
15
16
 
16
17
  T = TypeVar("T")
17
18
 
18
- # Default per-op timeout. Individual Superdoc SDK calls should complete well
19
- # under this — the value is a safety net so a WebSocket stall, Keryx downtime,
20
- # or pathological large-document remote-read loop surfaces an actionable SDK
21
- # error instead of wedging the calling thread until the outer Daytona
22
- # INSTRUCTION_TIMEOUT_SECONDS kill.
23
- DEFAULT_OP_TIMEOUT_SECONDS: float = 60.0
24
-
25
19
  _loop: asyncio.AbstractEventLoop | None = None
26
20
  _thread: threading.Thread | None = None
27
21
  _lock = threading.Lock()
@@ -39,6 +39,7 @@ from docx._execution import (
39
39
  current_execution_id,
40
40
  is_stale_execution,
41
41
  )
42
+ from docx._timeouts import timeout_for_commands
42
43
  from docx.commands import Command, is_response_bearing, must_flush_immediately
43
44
  from docx.errors import DocxError, FlushAllError
44
45
 
@@ -113,6 +114,7 @@ def _extract_partial_results(exc: BaseException) -> list[Any]:
113
114
  out.append(result)
114
115
  return out
115
116
 
117
+
116
118
  if TYPE_CHECKING:
117
119
  from docx._http_doc import HttpClient
118
120
 
@@ -223,18 +225,39 @@ def flush_all(*, strict: bool = False) -> None:
223
225
  sys.stderr.write(f"[docx-sdk] flush_all: {msg}\n")
224
226
 
225
227
  if failures:
226
- raise FlushAllError(failures)
228
+ raise FlushAllError(failures=failures)
227
229
 
228
230
 
229
231
  # ---------------------------------------------------------------------------
230
232
  # CommandBuffer
231
233
  # ---------------------------------------------------------------------------
232
234
 
233
- # Idle window before a pure-mutation buffer auto-flushes. Short by design —
234
- # the SDK's main consumer is agent code that fires sequential property
235
- # setters within milliseconds of each other; we just need to coalesce those
236
- # without holding writes back from Keryx for human-perceptible time.
237
- DEFAULT_AUTO_FLUSH_SECONDS: float = 0.1
235
+
236
+ def _default_auto_flush_seconds() -> float:
237
+ """Return the transparent-batching idle window.
238
+
239
+ A very small window streams single edits quickly, but it can also flush
240
+ generated table-population loops halfway through the loop. That is painful
241
+ on large legal documents because each partial table batch can take longer
242
+ than the normal client timeout. Keep the default human-fast while giving
243
+ agent code enough room to coalesce common loops; allow local override for
244
+ debugging.
245
+ """
246
+ import os
247
+
248
+ raw = os.environ.get("ATHENA_DOCX_AUTO_FLUSH_SECONDS")
249
+ if raw is None:
250
+ return 1.0
251
+ try:
252
+ return max(float(raw), 0.0)
253
+ except ValueError:
254
+ return 1.0
255
+
256
+
257
+ # Idle window before a pure-mutation buffer auto-flushes. Agent-generated
258
+ # loops commonly perform dozens of property setters; a 1s window still feels
259
+ # live while avoiding mid-loop table flushes on large documents.
260
+ DEFAULT_AUTO_FLUSH_SECONDS: float = _default_auto_flush_seconds()
238
261
 
239
262
 
240
263
  class CommandBuffer:
@@ -305,6 +328,12 @@ class CommandBuffer:
305
328
  with self._lock:
306
329
  return len(self._pending)
307
330
 
331
+ @property
332
+ def pending_timeout_seconds(self) -> float:
333
+ with self._lock:
334
+ pending = list(self._pending)
335
+ return timeout_for_commands(commands=pending)
336
+
308
337
  @property
309
338
  def is_stale_for_current_execution(self) -> bool:
310
339
  return is_stale_execution(self._execution_id)
@@ -476,10 +505,13 @@ class CommandBuffer:
476
505
  return
477
506
  try:
478
507
  if self.is_stale_for_current_execution:
508
+ pending: list[Command]
479
509
  with self._lock:
480
510
  self._cancel_timer_locked()
511
+ pending = self._pending
481
512
  self._pending = []
482
513
  self._proxy_id_refs = {}
514
+ _ptc_emit_end_batch(pending, is_error=True)
483
515
  else:
484
516
  self.flush()
485
517
  finally:
@@ -553,6 +585,8 @@ class CommandBuffer:
553
585
  self._timer = None
554
586
 
555
587
  def _auto_flush(self) -> None:
588
+ if self.is_stale_for_current_execution:
589
+ return
556
590
  try:
557
591
  self.flush()
558
592
  except Exception as e: # noqa: BLE001
@@ -38,6 +38,7 @@ from requests.adapters import HTTPAdapter
38
38
  from urllib3.util.retry import Retry
39
39
 
40
40
  from docx._buffer import CommandBuffer
41
+ from docx._timeouts import timeout_for_commands
41
42
  from docx.commands import (
42
43
  BlocksList,
43
44
  BookmarksGet,
@@ -86,6 +87,7 @@ from docx.commands import (
86
87
  FieldsRefresh,
87
88
  Find,
88
89
  FindReplace,
90
+ FindText,
89
91
  FootnotesDelete,
90
92
  FootnotesGet,
91
93
  FootnotesList,
@@ -210,9 +212,7 @@ def _looks_like_block_not_found(err_obj: dict) -> bool:
210
212
  return False
211
213
  lower = msg.lower()
212
214
  if "not found" in lower:
213
- return 'block "' in lower or (
214
- 'block ' in lower and ' was not found' in lower
215
- )
215
+ return 'block "' in lower or ("block " in lower and " was not found" in lower)
216
216
  if "invalid_target" in lower or "invalid target" in lower:
217
217
  # "Expected paragraph:<id> but found tableCell:<id>" — the new
218
218
  # variant of the § 13 cell-inner-paragraph addressing gap.
@@ -323,7 +323,7 @@ _TABLE_QUERY_COMMANDS: frozenset[str] = frozenset(
323
323
 
324
324
  _TABLE_CLIENT_ID_HINT: str = (
325
325
  "\n\nHint: this looks like a stale client-side table UUID "
326
- '(``t_xxxxxxxxxxxx``). Either an earlier batch in this execution '
326
+ "(``t_xxxxxxxxxxxx``). Either an earlier batch in this execution "
327
327
  "raised before the SDK could rewrite the Table proxy's id from the "
328
328
  "client UUID to the real SuperDoc id, OR the table belongs to a "
329
329
  "prior execution whose state has been discarded. Recover by calling "
@@ -521,8 +521,7 @@ def _http_post_json(
521
521
  if is_remote_disconnect:
522
522
  n_commands = (
523
523
  len(body.get("commands", []))
524
- if isinstance(body, dict)
525
- and isinstance(body.get("commands"), list)
524
+ if isinstance(body, dict) and isinstance(body.get("commands"), list)
526
525
  else 0
527
526
  )
528
527
  hint = (
@@ -608,13 +607,9 @@ def _http_post_json(
608
607
  if _looks_like_block_not_found(err_obj):
609
608
  cmd_type = err_obj.get("type")
610
609
  paragraph_targeting = (
611
- isinstance(cmd_type, str)
612
- and cmd_type in _PARAGRAPH_TARGETING_COMMANDS
613
- )
614
- table_query = (
615
- isinstance(cmd_type, str)
616
- and cmd_type in _TABLE_QUERY_COMMANDS
610
+ isinstance(cmd_type, str) and cmd_type in _PARAGRAPH_TARGETING_COMMANDS
617
611
  )
612
+ table_query = isinstance(cmd_type, str) and cmd_type in _TABLE_QUERY_COMMANDS
618
613
  if paragraph_targeting:
619
614
  hint = _CELL_PARAGRAPH_HINT
620
615
  elif table_query:
@@ -749,6 +744,7 @@ class HttpClient:
749
744
  url=url,
750
745
  api_key=self._api_key,
751
746
  body=body,
747
+ timeout=timeout_for_commands(commands=commands),
752
748
  )
753
749
  applied = resp.get("applied")
754
750
  # An empty applied list paired with an `error` field is the
@@ -881,7 +877,6 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
881
877
  "track_changes.list": TrackChangesList,
882
878
  "track_changes.get": TrackChangesGet,
883
879
  "track_changes.decide": TrackChangesDecide,
884
-
885
880
  # --- Athena-extension ops (v0.11.0) -----------------------------------
886
881
  # Mirror the dotted-path style of the upstream-parity routes above:
887
882
  # ``hyperlinks.create`` matches SuperDoc's ``doc.hyperlinks.create``.
@@ -928,6 +923,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
928
923
  "sdt.delete": ContentControlsDelete,
929
924
  "sections.set_columns": SetSectionColumns,
930
925
  "find_replace": FindReplace,
926
+ "find_text": FindText,
931
927
  "iter_runs": IterRuns,
932
928
  "export_pdf": ExportPDF,
933
929
  "numbering.get": NumberingGet,
@@ -968,6 +964,7 @@ _FIELD_RENAMES: dict[str, dict[str, str]] = {
968
964
  # path-proxy snake-case transform leaves `in` as a Python keyword
969
965
  # collision; rename to `in_` here so the dataclass accepts it.
970
966
  "find_replace": {"in": "in_"},
967
+ "find_text": {"in": "in_"},
971
968
  "iter_runs": {"in": "in_"},
972
969
  "numbering.list": {"in": "in_"},
973
970
  }
@@ -983,9 +980,7 @@ def _build_command(op: str, params: dict[str, Any]) -> Command:
983
980
  )
984
981
 
985
982
  # Convert param keys camelCase → snake_case to match dataclass fields.
986
- snake_params: dict[str, Any] = {
987
- _camel_to_snake(k): v for k, v in params.items()
988
- }
983
+ snake_params: dict[str, Any] = {_camel_to_snake(k): v for k, v in params.items()}
989
984
 
990
985
  # Apply per-op renames (e.g. find: type → node_type).
991
986
  renames = _FIELD_RENAMES.get(op)
@@ -0,0 +1,32 @@
1
+ """Timeout budgets for SDK operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ DEFAULT_OP_TIMEOUT_SECONDS: float = 60.0
8
+
9
+ # Large document-wide primitives can be intentionally expensive while still
10
+ # being the safest path for agents. Keep the normal SDK budget tight, but give
11
+ # these one-shot commands enough room to finish on dense legal documents.
12
+ LONG_RUNNING_COMMAND_TIMEOUT_SECONDS: float = 300.0
13
+
14
+ _LONG_RUNNING_COMMAND_TYPES: frozenset[str] = frozenset(
15
+ {
16
+ "FindReplace",
17
+ # Plain ``cell.text = value`` table fills are buffered as TableSetCell
18
+ # commands. On dense legal documents, SuperDoc can spend well over the
19
+ # ordinary 60s budget committing a table batch even when the Python code
20
+ # uses the fast no-read cell path.
21
+ "TableSetCell",
22
+ }
23
+ )
24
+
25
+
26
+ def timeout_for_commands(*, commands: list[Any]) -> float:
27
+ """Return the HTTP timeout budget for a batch of command objects."""
28
+ for command in commands:
29
+ command_type = getattr(command, "type", type(command).__name__)
30
+ if command_type in _LONG_RUNNING_COMMAND_TYPES:
31
+ return LONG_RUNNING_COMMAND_TIMEOUT_SECONDS
32
+ return DEFAULT_OP_TIMEOUT_SECONDS
@@ -23,6 +23,7 @@ from contextlib import asynccontextmanager
23
23
  from typing import TYPE_CHECKING, Any
24
24
 
25
25
  from docx._execution import assert_current_execution, current_execution_id
26
+ from docx._timeouts import DEFAULT_OP_TIMEOUT_SECONDS
26
27
  from docx.errors import (
27
28
  AuthenticationError,
28
29
  DocumentClosedError,
@@ -99,6 +100,21 @@ class Session:
99
100
  def is_open(self) -> bool:
100
101
  return self._opened and not self._closed
101
102
 
103
+ @property
104
+ def pending_timeout_seconds(self) -> float:
105
+ handle = self._doc_handle
106
+ buffer = getattr(handle, "buffer", None) if handle is not None else None
107
+ timeout = (
108
+ getattr(buffer, "pending_timeout_seconds", DEFAULT_OP_TIMEOUT_SECONDS)
109
+ if buffer is not None
110
+ else DEFAULT_OP_TIMEOUT_SECONDS
111
+ )
112
+ if isinstance(timeout, bool):
113
+ return DEFAULT_OP_TIMEOUT_SECONDS
114
+ if isinstance(timeout, (int, float)):
115
+ return float(timeout)
116
+ return DEFAULT_OP_TIMEOUT_SECONDS
117
+
102
118
  async def open(self) -> None:
103
119
  """Construct the HTTP client + buffered doc handle.
104
120
 
@@ -1510,6 +1510,27 @@ class FindReplace(Command):
1510
1510
  max_replacements: int | None = None
1511
1511
 
1512
1512
 
1513
+ @dataclass
1514
+ class FindText(Command):
1515
+ """Search document text and return bounded match context.
1516
+
1517
+ Athena extension beyond python-docx 1.x. This is the read-side
1518
+ companion to :class:`FindReplace`: it avoids exporting a full
1519
+ ``.docx`` or walking every paragraph/run when callers only need a
1520
+ match count plus a few snippets. ``max_results`` limits how many
1521
+ contexts come back; ``count`` in the result remains the total
1522
+ number of matches found.
1523
+ """
1524
+
1525
+ pattern: str = ""
1526
+ regex: bool | None = None
1527
+ match_case: bool | None = None
1528
+ whole_word: bool | None = None
1529
+ in_: str | dict[str, Any] | None = None
1530
+ max_results: int | None = None
1531
+ context_chars: int | None = None
1532
+
1533
+
1513
1534
  @dataclass
1514
1535
  class IterRuns(Command):
1515
1536
  """Stream runs across the document (with story locator + offset)
@@ -1637,6 +1658,7 @@ _QUERY_TYPES: frozenset[str] = frozenset(
1637
1658
  "ContentControlsGet",
1638
1659
  "NumberingGet",
1639
1660
  "NumberingList",
1661
+ "FindText",
1640
1662
  "IterRuns",
1641
1663
  }
1642
1664
  )
@@ -1741,9 +1763,7 @@ from docx._athena_extension import ( # noqa: E402 — local circular import saf
1741
1763
  )
1742
1764
 
1743
1765
 
1744
- def _mark_athena_extension_command(
1745
- cls: type, issue: "str | None", description: str
1746
- ) -> None:
1766
+ def _mark_athena_extension_command(cls: type, issue: "str | None", description: str) -> None:
1747
1767
  setattr(cls, ATHENA_EXTENSION_ATTR, True)
1748
1768
  # ``issue`` is ``None`` for additions that don't have a 1:1 upstream
1749
1769
  # python-docx issue — typically things that are *not* missing from
@@ -1799,6 +1819,7 @@ for _cls, _issue, _desc in [
1799
1819
  (ContentControlsDelete, "python-docx#155", "SDT delete"),
1800
1820
  (SetSectionColumns, "python-docx#167", "Section multi-column layout"),
1801
1821
  (FindReplace, "python-docx#30", "Formatting-preserving find/replace"),
1822
+ (FindText, "python-docx#980", "Fast document text search"),
1802
1823
  (IterRuns, "python-docx#980", "Run stream for run-isolation"),
1803
1824
  (ExportPDF, "python-docx#113", "PDF export"),
1804
1825
  (ExportDocx, None, "DOCX export — local file roundtrip"),
@@ -1931,6 +1952,7 @@ __all__ = [
1931
1952
  "ContentControlsDelete",
1932
1953
  "SetSectionColumns",
1933
1954
  "FindReplace",
1955
+ "FindText",
1934
1956
  "IterRuns",
1935
1957
  "ExportPDF",
1936
1958
  "ExportDocx",