athena-python-docx 0.8.0__tar.gz → 0.10.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 (325) hide show
  1. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/CLAUDE.md +40 -4
  2. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_buffer.py +127 -75
  5. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_http_doc.py +144 -22
  6. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_ptc.py +32 -49
  7. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/api.py +56 -8
  8. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/commands.py +28 -0
  9. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/document.py +86 -78
  10. athena_python_docx-0.10.0/docx/errors.py +166 -0
  11. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/table.py +90 -48
  12. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/pyproject.toml +1 -1
  13. athena_python_docx-0.10.0/scripts/smoke_test_block_not_found.py +175 -0
  14. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/fake_session.py +68 -0
  15. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +12 -0
  16. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -1
  17. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/18_table_cell_text.json +9 -0
  18. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -3
  19. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +1 -4
  20. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/23_nested_table.json +1 -4
  21. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +1 -3
  22. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -2
  23. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/35_full_report.json +9 -33
  24. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/40_large_table_10x10.json +103 -0
  25. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +1 -5
  26. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/49_resume_layout.json +3 -12
  27. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +1 -4
  28. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +12 -48
  29. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +1 -4
  30. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -1
  31. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +793 -1993
  32. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/68_invoice.json +62 -0
  33. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -1
  34. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/72_legal_contract.json +6 -24
  35. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +20 -80
  36. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +9 -27
  37. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +24 -0
  38. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -1
  39. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/91_many_small_tables.json +153 -0
  40. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +1 -4
  41. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +3 -12
  42. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex04_50x50_table.json +53 -0
  43. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +5 -0
  44. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/mega10_api_documentation.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex10_complex_bom.json +126 -113
  45. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +80 -320
  46. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -1
  47. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/rw10_colored_grid_table.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex14_styled_report_table.json +36 -69
  48. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +84 -336
  49. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +13 -52
  50. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +18 -72
  51. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +21 -98
  52. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +20 -88
  53. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/ex14_styled_report_table.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +44 -75
  54. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +8 -36
  55. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/mega10_api_documentation.json +104 -97
  56. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +12 -36
  57. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +12 -36
  58. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/rw08_table_merged_header.json +13 -0
  59. athena_python_docx-0.10.0/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +148 -0
  60. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +1 -4
  61. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/baseline_gaps.json +1 -1
  62. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/reports/GAP_ANALYSIS.md +1 -1
  63. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/reports/gap_report.json +1 -1
  64. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/snapshots/athena_latest.json +201 -1
  65. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_block_not_found_error.py +52 -11
  66. athena_python_docx-0.10.0/tests/test_document_asset_id_property.py +52 -0
  67. athena_python_docx-0.10.0/tests/test_document_factory_validation.py +52 -0
  68. athena_python_docx-0.10.0/tests/test_e2e_partial_failure_cascade.py +278 -0
  69. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_parity_misc.py +4 -2
  70. athena_python_docx-0.10.0/tests/test_partial_failure_cascade.py +346 -0
  71. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_ptc.py +246 -10
  72. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_document_audit.py +55 -61
  73. athena_python_docx-0.10.0/tests/test_table_set_cell_perf.py +127 -0
  74. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_wire_contract.py +9 -0
  75. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/uv.lock +1 -1
  76. athena_python_docx-0.8.0/docx/errors.py +0 -88
  77. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -24
  78. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -27
  79. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -403
  80. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/68_invoice.json +0 -114
  81. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -54
  82. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -453
  83. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -203
  84. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -8
  85. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -596
  86. athena_python_docx-0.8.0/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -35
  87. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/.gitignore +0 -0
  88. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/README.md +0 -0
  89. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_batching.py +0 -0
  90. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_http.py +0 -0
  91. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/_image_utils.py +0 -0
  92. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/client.py +0 -0
  93. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/comments.py +0 -0
  94. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/enum/__init__.py +0 -0
  95. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/enum/section.py +0 -0
  96. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/enum/style.py +0 -0
  97. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/enum/table.py +0 -0
  98. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/enum/text.py +0 -0
  99. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/exceptions.py +0 -0
  100. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/opc/__init__.py +0 -0
  101. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/opc/coreprops.py +0 -0
  102. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/oxml/__init__.py +0 -0
  103. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/revisions.py +0 -0
  104. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/section.py +0 -0
  105. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/settings.py +0 -0
  106. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/shape.py +0 -0
  107. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/shared.py +0 -0
  108. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/styles/__init__.py +0 -0
  109. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/styles/style.py +0 -0
  110. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/styles/styles.py +0 -0
  111. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/__init__.py +0 -0
  112. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/font.py +0 -0
  113. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/hyperlink.py +0 -0
  114. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/pagebreak.py +0 -0
  115. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/paragraph.py +0 -0
  116. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/parfmt.py +0 -0
  117. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/run.py +0 -0
  118. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/text/tabstops.py +0 -0
  119. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/docx/typing.py +0 -0
  120. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/scripts/publish.sh +0 -0
  121. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/scripts/release.sh +0 -0
  122. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/scripts/round_trip_smoke.py +0 -0
  123. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/__init__.py +0 -0
  124. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/conftest.py +0 -0
  125. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/METHODOLOGY.md +0 -0
  126. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/README.md +0 -0
  127. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/__init__.py +0 -0
  128. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/ab_probe_cases.py +0 -0
  129. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/ab_probe_runner.py +0 -0
  130. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/auto_gen_cases.py +0 -0
  131. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/binary_round_trip.py +0 -0
  132. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/cases.py +0 -0
  133. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/complex_cases.py +0 -0
  134. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/coverage_report.py +0 -0
  135. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/extract.py +0 -0
  136. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/extreme_cases.py +0 -0
  137. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/local_runner.py +0 -0
  138. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/mega_cases.py +0 -0
  139. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshot.py +0 -0
  140. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  141. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  142. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  143. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  144. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  145. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  146. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  147. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  148. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  149. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  150. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  151. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  152. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  153. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  154. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  155. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  156. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  157. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  158. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  159. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  160. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  161. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  162. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  163. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  164. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  165. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  166. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  167. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  168. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  169. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  170. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  171. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  172. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  173. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  174. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  175. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  176. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  177. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  178. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  179. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  180. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  181. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  182. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  183. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  184. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  185. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  186. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  187. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  188. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  189. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  190. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  191. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  192. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  193. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  194. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  195. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  196. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  197. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  198. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  199. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  200. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  201. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  202. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  203. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  204. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  205. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  206. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  207. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  208. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  209. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  210. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  211. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  212. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  213. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  214. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  215. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  216. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  217. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  218. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  219. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  220. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  221. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  222. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  223. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  224. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  225. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  226. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  227. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  228. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  229. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  230. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  231. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  232. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  233. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  234. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  235. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  236. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  237. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  238. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  239. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  240. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  241. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  242. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  243. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  244. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  245. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  246. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/ours_spec.json +0 -0
  247. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/parity_crawl.py +0 -0
  248. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/parity_diff.json +0 -0
  249. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/real_world_cases.py +0 -0
  250. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/round_trip_tests.py +0 -0
  251. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/runner.py +0 -0
  252. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/stock_spec.json +0 -0
  253. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  254. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/README.md +0 -0
  255. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/__init__.py +0 -0
  256. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/compare.py +0 -0
  257. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/intentional_deviations.json +0 -0
  258. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/introspect.py +0 -0
  259. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/run_parity.py +0 -0
  260. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  261. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/parity/test_parity_gap.py +0 -0
  262. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_batching_perf.py +0 -0
  263. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_buffer.py +0 -0
  264. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  265. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_collapsed_range_format.py +0 -0
  266. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_command_dataclasses.py +0 -0
  267. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_commands.py +0 -0
  268. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_comments.py +0 -0
  269. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_document_create.py +0 -0
  270. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_http_transport.py +0 -0
  271. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_hyperlink_coalescing.py +0 -0
  272. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_insert_deferred.py +0 -0
  273. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_iter_inner_content.py +0 -0
  274. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_list_styles.py +0 -0
  275. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_merged_cells.py +0 -0
  276. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_oxml_shim.py +0 -0
  277. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_paragraph_text_len_cache.py +0 -0
  278. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_parity_round2.py +0 -0
  279. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_phase_a_behavior.py +0 -0
  280. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_phase_b_headers_footers.py +0 -0
  281. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_phase_c_tables.py +0 -0
  282. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_pr19766_review_fixes.py +0 -0
  283. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_python_docx_api_parity.py +0 -0
  284. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_revisions.py +0 -0
  285. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  286. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_picture.py +0 -0
  287. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_run.py +0 -0
  288. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  289. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  290. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_comments_get.py +0 -0
  291. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_document_element.py +0 -0
  292. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_enum_section.py +0 -0
  293. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_font_audit.py +0 -0
  294. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_header_footer.py +0 -0
  295. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_hyperlink.py +0 -0
  296. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_inline_shape.py +0 -0
  297. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  298. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_misc.py +0 -0
  299. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  300. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  301. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  302. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_parfmt.py +0 -0
  303. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  304. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_add_break.py +0 -0
  305. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  306. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_style.py +0 -0
  307. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  308. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_text.py +0 -0
  309. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_underline.py +0 -0
  310. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_audit.py +0 -0
  311. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  312. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_onoff.py +0 -0
  313. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_settings.py +0 -0
  314. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_shared_audit.py +0 -0
  315. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_style.py +0 -0
  316. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_styles.py +0 -0
  317. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_audit.py +0 -0
  318. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_cell.py +0 -0
  319. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  320. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_layout.py +0 -0
  321. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_smoke_integration.py +0 -0
  322. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_style_acceptance.py +0 -0
  323. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_style_font.py +0 -0
  324. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_style_setters_contract.py +0 -0
  325. {athena_python_docx-0.8.0 → athena_python_docx-0.10.0}/tests/test_zod_wire_contract.py +0 -0
@@ -88,13 +88,28 @@ not file-backed. Each is documented in the relevant docstring.
88
88
  hits `POST {base_url}/docs/empty`. The constructor positional-arg
89
89
  shape (`Document(asset_id)`) is preserved for parity.
90
90
 
91
- - **`Document.save(path_or_stream=None)`** — argument is optional.
92
- Stock python-docx requires it and `TypeError`s on no-arg, but in an
91
+ - **`Document.asset_id: str`** read-only property the Athena asset
92
+ id this Document is bound to (`asset_<uuid>`). Agent-callable so
93
+ the typical pattern `doc = Document.create(...); print(doc.asset_id)`
94
+ works without reaching into `doc._session._asset_id`. Stock
95
+ python-docx has no analogue (it operates on local files), so this
96
+ is an Athena-only addition. Mirrors the parallel public accessors
97
+ on the other studios: `Workbook.workbook_id` (xlsx) and
98
+ `Presentation.deck_id` (pptx).
99
+
100
+ - **`Document.save(path_or_stream=None)`** — argument is optional and,
101
+ when supplied, raises
102
+ :class:`docx.errors.LocalSaveTargetNotSupportedError`. Stock
103
+ python-docx requires it and `TypeError`s on no-arg, but in an
93
104
  asset-backed SDK there is no local file to write — writes are always
94
105
  in-place against the Y.Doc. Forcing the upstream signature broke
95
106
  every agent invocation that reflexively called `doc.save()` (a
96
- near-universal Python pattern), so we accept it for parity-friendly
97
- call sites and ignore the value at runtime.
107
+ near-universal Python pattern), so the no-arg form is supported.
108
+ When a path or stream IS supplied, the SDK cannot fulfill the
109
+ implied "write bytes to this target" contract, so the call raises
110
+ loudly rather than silently flushing — agents must use Olympus's
111
+ Export DOCX (which goes through the SuperDoc session that already
112
+ has the bytes) instead of expecting a local file.
98
113
 
99
114
  - **`Document.track_revisions: bool`** — when `True`, all subsequent
100
115
  mutations are recorded as tracked revisions instead of direct edits.
@@ -181,6 +196,27 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
181
196
  and the follow-up `doc.insert` is buffered, so plain cell
182
197
  assignments are 0 HTTP requests until the next flush. See
183
198
  ``docx.table._is_plain_text`` for the trigger predicate.
199
+ - **Partial-failure cascade fix (0.9.0+):** when an HTTP batch raises
200
+ on a 207 partial-failure (e.g. one cell-paragraph mistake mid-script),
201
+ the SDK now rewrites ``proxy_id_refs`` for the ``applied`` prefix
202
+ the server reports as successful — BEFORE re-raising. Pre-0.9.0 the
203
+ rewrite was inside the success-path-only branch, so every Create that
204
+ committed server-side left its Python proxy stuck on the client UUID;
205
+ the next batch shipped dead client UUIDs and the cascade restarted.
206
+ Preview-session ``thread_bafba02b`` turned one cell-paragraph error
207
+ into thirteen downstream "Block not found" failures + a
208
+ ``DOCUMENT_IDENTITY_CONFLICT`` before this fix. The path goes
209
+ ``_http_post_json`` (attaches ``applied[]`` via
210
+ ``DocxError.with_partial_applied``) → ``CommandBuffer.flush`` /
211
+ ``_eager_flush_with`` (catches ``DocxError``, drains the prefix
212
+ through ``_apply_proxy_id_rewrites``, re-raises). See
213
+ ``tests/test_partial_failure_cascade.py`` for the contract.
214
+ - **Table-query hint (0.9.0+):** ``BlockNotFoundError`` on
215
+ ``TablesGet`` / ``TablesGetCells`` / etc. used to fall through with
216
+ no hint (the cell-paragraph workaround doesn't apply). Now carries
217
+ a dedicated "stale client-table-UUID" hint pointing at the actual
218
+ recovery (``doc.save()`` to drain pending + re-anchor proxies). See
219
+ ``_TABLE_CLIENT_ID_HINT`` in ``docx/_http_doc.py``.
184
220
  - The path-proxy in `_http_doc.py` is an internal translation layer:
185
221
  call sites that look like `await self._session.doc.create.paragraph(p)`
186
222
  resolve to `CommandBuffer.call(CreateParagraph(**p))`. Rewriting call
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-docx
3
- Version: 0.8.0
3
+ Version: 0.10.0
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>
@@ -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.8.0"
9
+ __version__ = "0.10.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import flush_all
@@ -35,11 +35,94 @@ from typing import TYPE_CHECKING, Any
35
35
 
36
36
  from docx import _ptc
37
37
  from docx.commands import Command, is_response_bearing, must_flush_immediately
38
+ from docx.errors import DocxError
39
+
40
+
41
+ def _apply_proxy_id_rewrites(
42
+ results: list[Any],
43
+ proxy_id_refs: "dict[str, list[tuple[object, str]]]",
44
+ ) -> None:
45
+ """Walk ``results`` and rewrite registered proxy ids from client UUIDs
46
+ to the real SuperDoc ids the applier echoed back.
47
+
48
+ Shared by the success path in :meth:`CommandBuffer.flush` /
49
+ :meth:`_eager_flush_with` AND by the **partial-failure recovery
50
+ path** (the SDK now reads ``DocxError.partial_applied`` on raise
51
+ and applies the same rewrite for the prefix that committed before
52
+ the server hit its first failure). Without this, every Create that
53
+ succeeded server-side would leave its Python proxy stuck on the
54
+ client UUID and the next batch would ship the dead id straight
55
+ back to the server — that cascade is what turned one cell-
56
+ paragraph mistake in preview-session ``thread_bafba02b`` into
57
+ thirteen downstream "Block not found" errors.
58
+
59
+ Tolerant of legacy / transitional applier results that don't
60
+ include ``client_node_id`` / ``real_node_id`` echoes — we simply
61
+ leave those proxies on their client id; the applier's per-batch
62
+ ``clientIdMap`` rewrite still resolves them server-side on the
63
+ *next* call.
64
+ """
65
+ if not proxy_id_refs:
66
+ return
67
+ for result in results:
68
+ if not isinstance(result, dict):
69
+ continue
70
+ for cli_key, real_key in (
71
+ ("client_node_id", "real_node_id"),
72
+ ("client_entity_id", "real_entity_id"),
73
+ ):
74
+ cli = result.get(cli_key)
75
+ real = result.get(real_key)
76
+ if not (isinstance(cli, str) and isinstance(real, str)):
77
+ continue
78
+ refs = proxy_id_refs.pop(cli, [])
79
+ for proxy, attr in refs:
80
+ try:
81
+ setattr(proxy, attr, real)
82
+ except Exception: # noqa: BLE001
83
+ # A proxy that rejected setattr (slots without the
84
+ # attr, frozen dataclass, etc.) silently keeps its
85
+ # client_id — the applier's rewriter will still
86
+ # resolve it correctly on the next batch.
87
+ pass
88
+
89
+
90
+ def _extract_partial_results(exc: BaseException) -> list[Any]:
91
+ """Pull per-command ``result`` dicts out of a partial-failure error.
92
+
93
+ The HTTP layer attaches the server's ``applied`` array to
94
+ :class:`DocxError` (and subclasses) as ``partial_applied``. Each
95
+ entry is the wire-format ``{index, type, result}`` triple. We
96
+ return just the ``result`` dicts so the rewrite path can share its
97
+ success-path code without caring whether it's running on a happy
98
+ batch or a salvaged prefix.
99
+ """
100
+ applied = getattr(exc, "partial_applied", None)
101
+ if not isinstance(applied, list):
102
+ return []
103
+ out: list[Any] = []
104
+ for entry in applied:
105
+ if isinstance(entry, dict):
106
+ result = entry.get("result")
107
+ if isinstance(result, dict):
108
+ out.append(result)
109
+ return out
38
110
 
39
111
  if TYPE_CHECKING:
40
112
  from docx._http_doc import HttpClient
41
113
 
42
114
 
115
+ # Only commands whose class name is in this set produce PTC sub-tool-cards.
116
+ # Every Command subclass is a candidate, but each emit is now a synchronous
117
+ # HTTP POST to agora (see ``_ptc._send``), so emitting one card per low-level
118
+ # mutation produces hundreds of sub-cards per script and pays full network
119
+ # RTT on every one. The allow-list keeps the per-action signal — one card
120
+ # per logical paragraph creation — without the spam or the cumulative
121
+ # latency. Asset-level creation events (``CreateDocument``) are emitted
122
+ # from ``Document.create`` directly, not through this buffer path.
123
+ _PTC_EMIT_TOOLS: frozenset[str] = frozenset({"CreateParagraph"})
124
+
125
+
43
126
  def _ptc_emit_end_batch(cmds: list[Command], *, is_error: bool) -> None:
44
127
  """Emit a PTC ``end`` event for every cmd that received a ``begin``.
45
128
 
@@ -85,9 +168,7 @@ def _unregister(buffer: "CommandBuffer") -> None:
85
168
  """
86
169
  with _registry_lock:
87
170
  _active_buffers[:] = [
88
- ref
89
- for ref in _active_buffers
90
- if (b := ref()) is not None and b is not buffer
171
+ ref for ref in _active_buffers if (b := ref()) is not None and b is not buffer
91
172
  ]
92
173
 
93
174
 
@@ -170,14 +251,10 @@ class CommandBuffer:
170
251
  # real nodeId after flush. Populated by ``add_paragraph`` /
171
252
  # ``add_heading`` / etc. when they queue a Create with a
172
253
  # client-assigned id. Drained on every flush.
173
- self._proxy_id_refs: dict[
174
- str, list[tuple[object, str]]
175
- ] = {}
254
+ self._proxy_id_refs: dict[str, list[tuple[object, str]]] = {}
176
255
  _register(self)
177
256
 
178
- def register_proxy_id_ref(
179
- self, client_id: str, proxy: object, attr: str = "_node_id"
180
- ) -> None:
257
+ def register_proxy_id_ref(self, client_id: str, proxy: object, attr: str = "_node_id") -> None:
181
258
  """Register that ``proxy.<attr>`` should be rewritten from
182
259
  ``client_id`` to the real node id once the queue flushes.
183
260
 
@@ -215,9 +292,7 @@ class CommandBuffer:
215
292
  ``"direct"``, ``"tracked"``, or ``None`` to clear.
216
293
  """
217
294
  if mode is not None and mode not in ("direct", "tracked"):
218
- raise ValueError(
219
- f"change_mode must be 'direct', 'tracked', or None; got {mode!r}"
220
- )
295
+ raise ValueError(f"change_mode must be 'direct', 'tracked', or None; got {mode!r}")
221
296
  with self._lock:
222
297
  current = self._change_mode
223
298
  if current == mode:
@@ -269,16 +344,19 @@ class CommandBuffer:
269
344
  f"CommandBuffer for {self._asset_id} is closed",
270
345
  )
271
346
 
272
- # PTC begin: one event per user-facing method call, before any
273
- # batching. Failures here can't crash the user's code path.
274
- try:
275
- cmd._ptc_call_id = _ptc.emit_begin( # type: ignore[attr-defined]
276
- type(cmd).__name__,
277
- cmd.to_dict(),
278
- asset_id=self._asset_id,
279
- )
280
- except Exception: # noqa: BLE001
281
- pass
347
+ # PTC begin: emit only for commands in the allow-list. Other
348
+ # commands still flow through the buffer (and through the batched
349
+ # HTTP POST), they just don't produce a sub-tool-card. ``emit_end``
350
+ # is automatically skipped because no ``_ptc_call_id`` was set.
351
+ if type(cmd).__name__ in _PTC_EMIT_TOOLS:
352
+ try:
353
+ cmd._ptc_call_id = _ptc.emit_begin( # type: ignore[attr-defined]
354
+ type(cmd).__name__,
355
+ cmd.to_dict(),
356
+ asset_id=self._asset_id,
357
+ )
358
+ except Exception: # noqa: BLE001
359
+ pass
282
360
 
283
361
  if must_flush_immediately(cmd) and not self._has_client_id(cmd):
284
362
  return self._eager_flush_with(cmd)
@@ -300,12 +378,9 @@ class CommandBuffer:
300
378
  legacy callers) keep their eager-flush semantics so callers
301
379
  that read the response still see real data.
302
380
  """
303
- return (
304
- is_response_bearing(cmd)
305
- and (
306
- getattr(cmd, "client_node_id", None) is not None
307
- or getattr(cmd, "client_entity_id", None) is not None
308
- )
381
+ return is_response_bearing(cmd) and (
382
+ getattr(cmd, "client_node_id", None) is not None
383
+ or getattr(cmd, "client_entity_id", None) is not None
309
384
  )
310
385
 
311
386
  def flush(self) -> list[Any]:
@@ -339,37 +414,22 @@ class CommandBuffer:
339
414
  change_mode=change_mode,
340
415
  user=user,
341
416
  )
417
+ except DocxError as exc:
418
+ # Partial-failure cascade protection: even though the batch
419
+ # raised, the server's ``applied`` prefix tells us which
420
+ # commands DID commit before the failure. Rewrite the
421
+ # corresponding proxy ids before re-raising so the next
422
+ # batch ships REAL ids for the survivors (vs. dead client
423
+ # UUIDs that would cascade into another "Block not found").
424
+ # See ``_apply_proxy_id_rewrites`` for the full rationale.
425
+ _apply_proxy_id_rewrites(_extract_partial_results(exc), proxy_id_refs)
426
+ _ptc_emit_end_batch(pending, is_error=True)
427
+ raise
342
428
  except Exception:
343
429
  _ptc_emit_end_batch(pending, is_error=True)
344
430
  raise
345
431
  _ptc_emit_end_batch(pending, is_error=False)
346
- # Rewrite registered proxies from client-side UUIDs to the real
347
- # SuperDoc ids the applier echoed back. Defensive: tolerate
348
- # missing fields (legacy or transitional applier without the
349
- # client-id support).
350
- if proxy_id_refs:
351
- for result in results:
352
- if not isinstance(result, dict):
353
- continue
354
- for cli_key, real_key in (
355
- ("client_node_id", "real_node_id"),
356
- ("client_entity_id", "real_entity_id"),
357
- ):
358
- cli = result.get(cli_key)
359
- real = result.get(real_key)
360
- if not (isinstance(cli, str) and isinstance(real, str)):
361
- continue
362
- refs = proxy_id_refs.pop(cli, [])
363
- for proxy, attr in refs:
364
- try:
365
- setattr(proxy, attr, real)
366
- except Exception: # noqa: BLE001
367
- # A proxy that rejected setattr (slots without
368
- # the attr, frozen dataclass, etc.) silently
369
- # keeps its client_id — the rewriter in the
370
- # applier will still resolve it correctly
371
- # for the next batch.
372
- pass
432
+ _apply_proxy_id_rewrites(results, proxy_id_refs)
373
433
  return results
374
434
 
375
435
  def close(self) -> None:
@@ -409,30 +469,22 @@ class CommandBuffer:
409
469
  change_mode=change_mode,
410
470
  user=user,
411
471
  )
472
+ except DocxError as exc:
473
+ # Same partial-failure cascade protection as :meth:`flush` —
474
+ # rewrite proxy ids for the prefix the server reports as
475
+ # ``applied`` before re-raising. Critical here because the
476
+ # eager-flush path is hit by every query in user code (e.g.
477
+ # ``table.cell(0, 0)`` → ``tables.get``), so a failure on
478
+ # the trailing ``cmd`` would otherwise abandon every
479
+ # buffered Create's rewrite at once.
480
+ _apply_proxy_id_rewrites(_extract_partial_results(exc), proxy_id_refs)
481
+ _ptc_emit_end_batch(all_cmds, is_error=True)
482
+ raise
412
483
  except Exception:
413
484
  _ptc_emit_end_batch(all_cmds, is_error=True)
414
485
  raise
415
486
  _ptc_emit_end_batch(all_cmds, is_error=False)
416
- # Apply the same proxy-rewrite pass as ``flush()`` — see comment
417
- # there for the contract.
418
- if proxy_id_refs:
419
- for result in results:
420
- if not isinstance(result, dict):
421
- continue
422
- for cli_key, real_key in (
423
- ("client_node_id", "real_node_id"),
424
- ("client_entity_id", "real_entity_id"),
425
- ):
426
- cli = result.get(cli_key)
427
- real = result.get(real_key)
428
- if not (isinstance(cli, str) and isinstance(real, str)):
429
- continue
430
- refs = proxy_id_refs.pop(cli, [])
431
- for proxy, attr in refs:
432
- try:
433
- setattr(proxy, attr, real)
434
- except Exception: # noqa: BLE001
435
- pass
487
+ _apply_proxy_id_rewrites(results, proxy_id_refs)
436
488
  if not results:
437
489
  return {}
438
490
  return results[-1]
@@ -30,6 +30,7 @@ format is now typed end-to-end either way.
30
30
  from __future__ import annotations
31
31
 
32
32
  import json
33
+ import os
33
34
  from typing import Any
34
35
 
35
36
  import requests
@@ -106,6 +107,7 @@ from docx.commands import (
106
107
  TablesSetRowHeight,
107
108
  TablesSetStyle,
108
109
  TablesSetTableOptions,
110
+ TableSetCell,
109
111
  TrackChangesDecide,
110
112
  TrackChangesGet,
111
113
  TrackChangesList,
@@ -154,17 +156,102 @@ def _looks_like_block_not_found(err_obj: dict) -> bool:
154
156
  return 'block "' in lower or ('block ' in lower and ' was not found' in lower)
155
157
 
156
158
 
159
+ # Commands that target a paragraph block (or its inline range) and
160
+ # therefore trip the SuperDoc 1.8.1 cell-paragraph addressing gap when
161
+ # the target paragraph is nested inside a ``tableCell``. Used by the
162
+ # ``BlockNotFoundError`` hint logic to decide whether to surface the
163
+ # materialization workaround. Membership is checked against the
164
+ # ``err_obj["type"]`` field that ``apps/api`` echoes back on partial
165
+ # failure, so the gate covers both error-message shapes the SuperDoc
166
+ # CLI emits:
167
+ #
168
+ # * ``Block "paragraph:<uuid>" was not found.`` (SetParagraph*, etc.)
169
+ # * ``Block "<uuid>" not found.`` (Insert)
170
+ #
171
+ # Without this gate, the hint either fired for stale-id misses on
172
+ # unrelated command types (Greptile #20555) or skipped the Insert form
173
+ # entirely (preview session
174
+ # thread_b952794f, where 3 of 4 failures were bare-UUID Inserts and
175
+ # the agent burned 4 retries without ever seeing the workaround).
176
+ _PARAGRAPH_TARGETING_COMMANDS: frozenset[str] = frozenset(
177
+ {
178
+ "Insert",
179
+ "FormatApply",
180
+ "SetParagraphAlignment",
181
+ "ClearParagraphAlignment",
182
+ "SetParagraphStyle",
183
+ "SetParagraphIndentation",
184
+ "ClearParagraphIndentation",
185
+ "SetParagraphSpacing",
186
+ "ClearParagraphSpacing",
187
+ "SetParagraphKeepOptions",
188
+ "SetParagraphFlowOptions",
189
+ "SetParagraphTabStop",
190
+ "ClearParagraphTabStops",
191
+ "Replace",
192
+ "InsertLineBreak",
193
+ "InsertTab",
194
+ }
195
+ )
196
+
197
+
157
198
  _CELL_PARAGRAPH_HINT: str = (
158
199
  "\n\nHint: SuperDoc 1.8.1 cannot format paragraphs nested inside "
159
200
  "table cells via SetParagraphAlignment / SetParagraphStyle / "
160
- "SetParagraphIndentation / SetParagraphSpacing or doc.insert with "
161
- "a paragraph-block target. The cell's inner paragraph id is "
162
- "returned by cell.getNodeById but isn't a top-level addressable "
163
- "block. Materialize the cell's paragraph first via "
164
- '``cell.text = "value"``, then re-read ``cell.paragraphs[0]`` and '
165
- "apply format ops to that post-materialization Paragraph proxy. "
166
- "Tracked upstream at docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md "
167
- "§ 'cell-inner paragraph addressing'."
201
+ "SetParagraphIndentation / SetParagraphSpacing / doc.insert with "
202
+ "a paragraph-block target, or any FormatApply on a cell-inner run. "
203
+ "The cell's inner paragraph id is returned by cell.getNodeById but "
204
+ "isn't a top-level addressable block. Materialize the cell's "
205
+ 'paragraph first via ``cell.text = "value"``, then re-read '
206
+ "``cell.paragraphs[0]`` and apply format ops to that post-"
207
+ "materialization Paragraph proxy. Tracked upstream at "
208
+ "docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md § 'cell-inner paragraph "
209
+ "addressing'."
210
+ )
211
+
212
+
213
+ # ``tables.get`` / ``tables.getCells`` / ``tables.getProperties`` carry
214
+ # the table id at the top-level ``nodeId`` field — and the agent code
215
+ # that triggers them (``table.cell(0, 0)``, ``table.rows``, etc.) runs
216
+ # *immediately* after ``doc.add_table(...)``. The first such query
217
+ # triggers an eager flush that drains the buffered CreateTable in the
218
+ # same HTTP batch, so the applier's per-batch ``clientIdMap`` rewrite
219
+ # normally catches it. But when an EARLIER batch (e.g. a doomed cell-
220
+ # paragraph mutation a few lines up in the user script) raised before
221
+ # the SDK could rewrite ``proxy_id_refs``, the Table proxy still holds
222
+ # the client UUID. The next batch ships the dead id straight to SuperDoc
223
+ # and we land here. The hint points the agent at the canonical recovery
224
+ # pattern (force a save() to reseat the proxy refs, or split the
225
+ # offending mutation into its own execution).
226
+ _TABLE_QUERY_COMMANDS: frozenset[str] = frozenset(
227
+ {
228
+ "TablesGet",
229
+ "TablesGetCells",
230
+ "TablesGetProperties",
231
+ "TablesSetStyle",
232
+ "TablesSetLayout",
233
+ "TablesSetTableOptions",
234
+ "TablesSetCellProperties",
235
+ "TablesSetColumnWidth",
236
+ "TablesSetRowHeight",
237
+ "TablesInsertRow",
238
+ "TablesInsertColumn",
239
+ "TablesMergeCells",
240
+ }
241
+ )
242
+
243
+
244
+ _TABLE_CLIENT_ID_HINT: str = (
245
+ "\n\nHint: this looks like a stale client-side table UUID "
246
+ '(``t_xxxxxxxxxxxx``). Either an earlier batch in this execution '
247
+ "raised before the SDK could rewrite the Table proxy's id from the "
248
+ "client UUID to the real SuperDoc id, OR the table belongs to a "
249
+ "prior execution whose state has been discarded. Recover by calling "
250
+ "``doc.save()`` to drain pending mutations + re-anchor live "
251
+ "proxies, then re-query via ``doc.tables`` to get fresh proxies "
252
+ "with real ids. If you saw a cell-paragraph error in the same "
253
+ "execution, address that first — its partial-failure is what "
254
+ "abandoned the rewrite."
168
255
  )
169
256
 
170
257
 
@@ -287,6 +374,9 @@ def _http_post_json(
287
374
  "Accept": "application/json",
288
375
  "User-Agent": _user_agent(),
289
376
  }
377
+ custom_attr = os.environ.get("ATHENA_DOCX_CUSTOM_ATTRIBUTIONS")
378
+ if custom_attr:
379
+ headers["X-Custom-Attributions"] = custom_attr
290
380
  try:
291
381
  resp = session.post(
292
382
  url,
@@ -314,6 +404,20 @@ def _http_post_json(
314
404
  parsed = json.loads(body) if body else {}
315
405
  except json.JSONDecodeError:
316
406
  parsed = {"raw": body}
407
+ # Extract the ``applied`` prefix so callers can rewrite
408
+ # ``proxy_id_refs`` for commands that DID succeed before the
409
+ # batch hit its first failure. Without this, the SDK throws
410
+ # away every successful Create's client-UUID → real-id mapping
411
+ # the moment ONE command fails, and the next batch keeps
412
+ # shipping dead client UUIDs. That cascade turned the preview-
413
+ # session thread_bafba02b's first cell-paragraph mistake into
414
+ # thirteen downstream "Block not found" errors and finally a
415
+ # ``DOCUMENT_IDENTITY_CONFLICT``. The structure is wire-shape:
416
+ # ``[{index, type, result: {client_node_id, real_node_id, …}}]``.
417
+ applied_raw = parsed.get("applied") if isinstance(parsed, dict) else None
418
+ partial_applied: list[dict] = []
419
+ if isinstance(applied_raw, list):
420
+ partial_applied = [a for a in applied_raw if isinstance(a, dict)]
317
421
  # If the failing command's error looks like "no such entity",
318
422
  # raise a typed :class:`NotFoundError` so speculative-read call
319
423
  # sites (``Comments.get``) can coerce it to ``None`` without
@@ -325,27 +429,44 @@ def _http_post_json(
325
429
  # likely targeting a cell-inner paragraph or stale-session
326
430
  # block id. Surface the typed exception plus an agent-readable
327
431
  # workaround so the next attempt doesn't repeat the same
328
- # mistake. The cell-paragraph hint only applies when the
329
- # missing id has the ``paragraph:`` prefix (SuperDoc's quoted-
330
- # id error format) stale list-item / table-row / image ids
331
- # would benefit from a different hint or none at all, and a
332
- # red-herring "use cell.text" pointer would just waste the
333
- # next retry.
432
+ # mistake.
433
+ #
434
+ # The cell-paragraph hint applies when the failing command is
435
+ # a paragraph-targeting op (Insert, FormatApply, SetParagraph*,
436
+ # …). We can't gate on the ``paragraph:`` prefix alone — the
437
+ # bare-UUID ``Block "<uuid>" not found.`` shape that SuperDoc's
438
+ # CLI emits for ``Insert`` failures is the dominant form of
439
+ # this bug in practice (preview-session thread_b952794f hit
440
+ # it 3 of 4 times without ever seeing the workaround under the
441
+ # prefix-only gate).
334
442
  if _looks_like_block_not_found(err_obj):
335
- msg_str = err_obj.get("message")
336
- paragraph_block = (
337
- isinstance(msg_str, str)
338
- and "paragraph:" in msg_str.lower()
443
+ cmd_type = err_obj.get("type")
444
+ paragraph_targeting = (
445
+ isinstance(cmd_type, str)
446
+ and cmd_type in _PARAGRAPH_TARGETING_COMMANDS
339
447
  )
448
+ table_query = (
449
+ isinstance(cmd_type, str)
450
+ and cmd_type in _TABLE_QUERY_COMMANDS
451
+ )
452
+ if paragraph_targeting:
453
+ hint = _CELL_PARAGRAPH_HINT
454
+ elif table_query:
455
+ hint = _TABLE_CLIENT_ID_HINT
456
+ else:
457
+ hint = ""
340
458
  raise BlockNotFoundError(
341
- base_msg + (_CELL_PARAGRAPH_HINT if paragraph_block else ""),
459
+ base_msg + hint,
342
460
  payload=err_obj,
343
- )
461
+ ).with_partial_applied(partial_applied)
344
462
  if _looks_like_not_found(err_obj):
345
- raise NotFoundError(base_msg, payload=err_obj)
463
+ raise NotFoundError(
464
+ base_msg,
465
+ payload=err_obj,
466
+ ).with_partial_applied(partial_applied)
346
467
  raise DocxError(
347
468
  f"docx-studio batch reported a partial failure: {parsed!r}",
348
- )
469
+ ).with_partial_applied(partial_applied)
349
470
 
350
471
  if 200 <= resp.status_code < 300:
351
472
  try:
@@ -531,6 +652,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
531
652
  "tables.set_cell_properties": TablesSetCellProperties,
532
653
  "tables.set_column_width": TablesSetColumnWidth,
533
654
  "tables.set_row_height": TablesSetRowHeight,
655
+ "tables.set_cell": TableSetCell,
534
656
  # Images (mutations)
535
657
  "images.set_size": SetImageSize,
536
658
  "images.set_alt_text": SetImageAltText,