athena-python-docx 0.31.0__tar.gz → 0.33.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 (459) hide show
  1. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/AGENTS.md +6 -0
  2. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_run_order.py +39 -0
  5. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/commands.py +20 -4
  6. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/drawing/__init__.py +7 -2
  7. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/settings.py +12 -2
  8. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/table.py +33 -19
  9. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/hyperlink.py +7 -4
  10. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/pagebreak.py +65 -18
  11. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/paragraph.py +50 -13
  12. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/run.py +214 -20
  13. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/pyproject.toml +1 -1
  14. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/complex_cases.py +1 -1
  15. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/fake_session.py +2 -0
  16. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +1 -0
  17. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fixtures/field_reads.json +1 -0
  18. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/baseline.json +5 -106
  19. athena_python_docx-0.33.0/tests/live/fixture_scripts.py +188 -0
  20. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_drawing_image.py +38 -0
  21. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_enum_parity.py +4 -2
  22. athena_python_docx-0.33.0/tests/test_rendered_page_breaks.py +196 -0
  23. athena_python_docx-0.33.0/tests/test_run_break_inner_content.py +121 -0
  24. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_edges.py +25 -0
  25. athena_python_docx-0.33.0/tests/test_run_later_runs.py +580 -0
  26. athena_python_docx-0.33.0/tests/test_run_unmodeled_toggles.py +86 -0
  27. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_settings.py +33 -0
  28. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_table_layout.py +8 -6
  29. athena_python_docx-0.33.0/tests/test_table_direction.py +102 -0
  30. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/uv.lock +1 -1
  31. athena_python_docx-0.31.0/tests/live/fixture_scripts.py +0 -68
  32. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/.gitignore +0 -0
  33. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/CLAUDE.md +0 -0
  34. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/DOCX_EXEC_LAB.md +0 -0
  35. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/README.md +0 -0
  36. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_athena_extension.py +0 -0
  37. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_batching.py +0 -0
  38. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_buffer.py +0 -0
  39. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_capabilities.py +0 -0
  40. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_citations.py +0 -0
  41. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_execution.py +0 -0
  42. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_http.py +0 -0
  43. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_http_doc.py +0 -0
  44. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_image_utils.py +0 -0
  45. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_postproc.py +0 -0
  46. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_ptc.py +0 -0
  47. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_references.py +0 -0
  48. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_table_styles.py +0 -0
  49. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_timeouts.py +0 -0
  50. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/_tracked.py +0 -0
  51. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/api.py +0 -0
  52. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/blkcntnr.py +0 -0
  53. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/bookmarks.py +0 -0
  54. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/charts.py +0 -0
  55. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/client.py +0 -0
  56. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/comments.py +0 -0
  57. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/document.py +0 -0
  58. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/__init__.py +0 -0
  59. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/base.py +0 -0
  60. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/dml.py +0 -0
  61. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/section.py +0 -0
  62. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/shape.py +0 -0
  63. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/style.py +0 -0
  64. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/table.py +0 -0
  65. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/enum/text.py +0 -0
  66. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/errors.py +0 -0
  67. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/exceptions.py +0 -0
  68. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/fields.py +0 -0
  69. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/footnotes.py +0 -0
  70. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/image/__init__.py +0 -0
  71. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/image/exceptions.py +0 -0
  72. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/image/image.py +0 -0
  73. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/math.py +0 -0
  74. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/opc/__init__.py +0 -0
  75. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/opc/coreprops.py +0 -0
  76. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/oxml/__init__.py +0 -0
  77. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/revisions.py +0 -0
  78. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/sdt.py +0 -0
  79. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/section.py +0 -0
  80. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/session.py +0 -0
  81. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/shape.py +0 -0
  82. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/shared.py +0 -0
  83. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/styles/__init__.py +0 -0
  84. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/styles/_table.py +0 -0
  85. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/styles/latent.py +0 -0
  86. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/styles/style.py +0 -0
  87. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/styles/styles.py +0 -0
  88. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/__init__.py +0 -0
  89. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/font.py +0 -0
  90. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/parfmt.py +0 -0
  91. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/text/tabstops.py +0 -0
  92. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/toc.py +0 -0
  93. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/docx/typing.py +0 -0
  94. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/docx_exec_lab.py +0 -0
  95. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  96. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  97. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/docx_exec_lab_server.py +0 -0
  98. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/dump_wire_fixtures.py +0 -0
  99. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/release.sh +0 -0
  100. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/round_trip_smoke.py +0 -0
  101. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/smoke_test_block_not_found.py +0 -0
  102. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/scripts/validate_find_replace_asset.py +0 -0
  103. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/__init__.py +0 -0
  104. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/conftest.py +0 -0
  105. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/METHODOLOGY.md +0 -0
  106. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/README.md +0 -0
  107. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/__init__.py +0 -0
  108. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/ab_probe_cases.py +0 -0
  109. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/ab_probe_runner.py +0 -0
  110. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/auto_gen_cases.py +0 -0
  111. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/binary_round_trip.py +0 -0
  112. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/cases.py +0 -0
  113. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/coverage_report.py +0 -0
  114. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/extract.py +0 -0
  115. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/extreme_cases.py +0 -0
  116. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/README.md +0 -0
  117. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  118. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  119. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  120. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  121. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  122. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/local_runner.py +0 -0
  123. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/mega_cases.py +0 -0
  124. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshot.py +0 -0
  125. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  126. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  127. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  128. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  129. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  130. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  131. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  132. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  133. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  134. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  135. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  136. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  137. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  138. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  139. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  140. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  141. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  142. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  143. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  144. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  145. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  146. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  147. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  148. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  149. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  150. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  151. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  152. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  153. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  154. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  155. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  156. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  157. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  158. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  159. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  160. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  161. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  162. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  163. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  164. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  165. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  166. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  167. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  168. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  169. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  170. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  171. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  172. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  173. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  174. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  175. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  176. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  177. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  178. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  179. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  180. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  181. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  182. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  183. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  184. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  185. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  186. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  187. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  188. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  189. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  190. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  191. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  192. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  193. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  194. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  195. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  196. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  197. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  198. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  199. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  200. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  201. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  202. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  203. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  204. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  205. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  206. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  207. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  208. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  209. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  210. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  211. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  212. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  213. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  214. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  215. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  216. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  217. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  218. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  219. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  220. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  221. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  222. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  223. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  224. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  225. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  226. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  227. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  228. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  229. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  230. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  231. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  232. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  233. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  234. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  235. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  236. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  237. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  238. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  239. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  240. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  241. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  242. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  243. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  244. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  245. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  246. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  247. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  248. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  249. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  250. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  251. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  252. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  253. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  254. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  255. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  256. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  257. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  258. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  259. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  260. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  261. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  262. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  263. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  264. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  265. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  266. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  267. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  268. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  269. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  270. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  271. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  272. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  273. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  274. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  275. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  276. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/ours_spec.json +0 -0
  277. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/parity_crawl.py +0 -0
  278. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/parity_diff.json +0 -0
  279. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/real_world_cases.py +0 -0
  280. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/round_trip_tests.py +0 -0
  281. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/stock_spec.json +0 -0
  282. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  283. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fixtures/note_reference_reads.json +0 -0
  284. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fixtures/ruby_reads.json +0 -0
  285. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/fixtures/symbol_reads.json +0 -0
  286. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/__init__.py +0 -0
  287. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/reader.py +0 -0
  288. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/runner.py +0 -0
  289. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/sdk_driver.py +0 -0
  290. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/stock_driver.py +0 -0
  291. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/live/test_live_runner.py +0 -0
  292. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/README.md +0 -0
  293. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/__init__.py +0 -0
  294. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/baseline_gaps.json +0 -0
  295. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/compare.py +0 -0
  296. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/intentional_deviations.json +0 -0
  297. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/introspect.py +0 -0
  298. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  299. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/reports/gap_report.json +0 -0
  300. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/run_parity.py +0 -0
  301. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/snapshots/athena_latest.json +0 -0
  302. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  303. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/parity/test_parity_gap.py +0 -0
  304. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_add_section.py +0 -0
  305. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_add_section_extract_items.py +0 -0
  306. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  307. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_athena_extensions_contract.py +0 -0
  308. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_athena_extensions_registry.py +0 -0
  309. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_batch_chunking.py +0 -0
  310. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_batching_perf.py +0 -0
  311. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_block_not_found_error.py +0 -0
  312. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_buffer.py +0 -0
  313. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  314. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_add_table_not_supported.py +0 -0
  315. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_borders_spec.py +0 -0
  316. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_fastpath_runs.py +0 -0
  317. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  318. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  319. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_inner_format_stash.py +0 -0
  320. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  321. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_inner_run_guard.py +0 -0
  322. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_merge.py +0 -0
  323. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_nested_tables.py +0 -0
  324. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_paragraphs_listed.py +0 -0
  325. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  326. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_cell_text_replace_semantics.py +0 -0
  327. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_citations.py +0 -0
  328. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_collapsed_range_format.py +0 -0
  329. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_color_format_theme.py +0 -0
  330. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_command_dataclasses.py +0 -0
  331. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_commands.py +0 -0
  332. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_comment_paragraphs.py +0 -0
  333. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_comments.py +0 -0
  334. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_comments_first_read.py +0 -0
  335. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_content_control_value.py +0 -0
  336. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_core_properties.py +0 -0
  337. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_document_asset_id_property.py +0 -0
  338. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_document_clear.py +0 -0
  339. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_document_create.py +0 -0
  340. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_document_create_from_template.py +0 -0
  341. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_document_factory_validation.py +0 -0
  342. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_docx_exec_lab.py +0 -0
  343. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_docx_exec_lab_server.py +0 -0
  344. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  345. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_empty_hyperlinks.py +0 -0
  346. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_execution_scope.py +0 -0
  347. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_export_docx_clean.py +0 -0
  348. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_export_rescue_anchors.py +0 -0
  349. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  350. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_field_refresh.py +0 -0
  351. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_field_runs.py +0 -0
  352. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_find_replace_session_open.py +0 -0
  353. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_flushed_write_failures.py +0 -0
  354. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_http_transport.py +0 -0
  355. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_hyperlink_coalescing.py +0 -0
  356. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_image_url_data_uri.py +0 -0
  357. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_inline_page_break.py +0 -0
  358. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_inline_shape_alt_text.py +0 -0
  359. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_inline_shape_size.py +0 -0
  360. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_inline_shape_type.py +0 -0
  361. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_inline_shapes_floating.py +0 -0
  362. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_insert_deferred.py +0 -0
  363. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_iter_inner_content.py +0 -0
  364. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_list_styles.py +0 -0
  365. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  366. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_merged_cells.py +0 -0
  367. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_missing_modules.py +0 -0
  368. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_nested_table_refused.py +0 -0
  369. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  370. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_oxml_shim.py +0 -0
  371. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_page_break.py +0 -0
  372. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_paragraph_delete.py +0 -0
  373. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  374. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_paragraph_text_len_cache.py +0 -0
  375. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_parity_misc.py +0 -0
  376. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_parity_round2.py +0 -0
  377. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_partial_failure_cascade.py +0 -0
  378. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  379. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_phase_a_behavior.py +0 -0
  380. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_phase_b_headers_footers.py +0 -0
  381. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_phase_c_tables.py +0 -0
  382. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_positional_cell_id.py +0 -0
  383. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  384. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  385. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_postproc_ref_restore.py +0 -0
  386. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_pr19766_review_fixes.py +0 -0
  387. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_ptc.py +0 -0
  388. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_python_docx_api_parity.py +0 -0
  389. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_read_run_ranges.py +0 -0
  390. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_repeated_node_read.py +0 -0
  391. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_restart_numbering.py +0 -0
  392. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_revisions.py +0 -0
  393. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_round_trip_smoke_script.py +0 -0
  394. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  395. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_add_picture_anchor.py +0 -0
  396. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_formatting_wire.py +0 -0
  397. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_identity.py +0 -0
  398. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_mark_inheritance.py +0 -0
  399. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_table_style_objects.py +0 -0
  400. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_text_python_docx.py +0 -0
  401. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  402. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_sdk_reads_served.py +0 -0
  403. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_section_read_lengths.py +0 -0
  404. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  405. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_add_picture.py +0 -0
  406. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_add_run.py +0 -0
  407. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  408. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  409. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_comments_get.py +0 -0
  410. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_document_audit.py +0 -0
  411. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_document_element.py +0 -0
  412. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_enum_section.py +0 -0
  413. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_font_audit.py +0 -0
  414. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_header_footer.py +0 -0
  415. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_hyperlink.py +0 -0
  416. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_inline_shape.py +0 -0
  417. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  418. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_misc.py +0 -0
  419. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  420. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  421. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  422. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_parfmt.py +0 -0
  423. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  424. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_add_break.py +0 -0
  425. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  426. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_style.py +0 -0
  427. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  428. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_text.py +0 -0
  429. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_run_underline.py +0 -0
  430. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_section_audit.py +0 -0
  431. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  432. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_section_onoff.py +0 -0
  433. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_shared_audit.py +0 -0
  434. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_style.py +0 -0
  435. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_styles.py +0 -0
  436. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_table_audit.py +0 -0
  437. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_table_cell.py +0 -0
  438. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  439. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_smoke_integration.py +0 -0
  440. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_acceptance.py +0 -0
  441. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_font.py +0 -0
  442. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_formatting_writes.py +0 -0
  443. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_metadata_writes.py +0 -0
  444. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_names.py +0 -0
  445. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_setters_contract.py +0 -0
  446. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_style_tab_stops_read.py +0 -0
  447. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  448. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_table_anchors.py +0 -0
  449. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_table_read_reuse.py +0 -0
  450. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_table_set_cell_perf.py +0 -0
  451. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_table_style_id_resolution.py +0 -0
  452. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_temporarily_unavailable.py +0 -0
  453. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_text_control_characters.py +0 -0
  454. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_tracked_revisions_offsets.py +0 -0
  455. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_uv_lock_version.py +0 -0
  456. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  457. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_wire_contract.py +0 -0
  458. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_xml_attr_guard.py +0 -0
  459. {athena_python_docx-0.31.0 → athena_python_docx-0.33.0}/tests/test_zod_wire_contract.py +0 -0
@@ -107,6 +107,12 @@ pinned by focused tests and documented in
107
107
  `horz_dpi`, `width`, `scaled_dimensions`, …). A picture in a table cell or
108
108
  a header has no id to read its image by, so `.image` raises `ValueError`;
109
109
  an older docx-studio does not report pictures, so they are not runs there.
110
+ - **A run holding only a page or column break yields `""` from
111
+ `Run.iter_inner_content()`,** as python-docx reads a `w:br` of type `page`
112
+ or `column` as empty text; an empty run (a comment reference's) yields
113
+ nothing. docx-studio's read marks such a run with `break`, and
114
+ `Run.add_break` marks the run it adds one to. Against an older docx-studio,
115
+ which sends no `break`, a re-read run yields nothing.
110
116
  - **`Styles.latent_styles`** (`docx.styles.latent.LatentStyles`) reads
111
117
  the document's `<w:latentStyles>` (defaults and each `w:lsdException`)
112
118
  from docx-studio's `Info` (`includeStyles` → `latentStyles`), as python-docx
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.31.0
3
+ Version: 0.33.0
4
4
  Summary: Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack
5
5
  Project-URL: Homepage, https://athenaintelligence.ai
6
6
  Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
@@ -6,7 +6,7 @@ See CLAUDE.md for the API parity contract.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- __version__ = "0.31.0"
9
+ __version__ = "0.33.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -332,6 +332,45 @@ def note_picture(run: "Run", picture_id: str, offset: int, *, before: str | None
332
332
  record.pictures.insert(index, (picture_id, offset))
333
333
 
334
334
 
335
+ def read_stamp() -> int:
336
+ """The moment a read gives its runs (``Paragraph.runs``): a run ``add_run``
337
+ creates after it has a higher ``seq``."""
338
+ return next(_SEQ)
339
+
340
+
341
+ def later_runs_at_end(run: "Run") -> int | None:
342
+ """How many runs after ``run`` end where it does, by which docx-studio
343
+ tells ``run`` from them (``run.laterRuns``) where the offset cannot: an
344
+ empty run ``add_run()`` made after it, or one of breaks alone, ends there
345
+ too.
346
+
347
+ For a run ``add_run`` created, the runs it created after it; for a run a
348
+ read gave (``Paragraph.runs``), the later runs of that read and the runs
349
+ ``add_run`` created since. Each where it ends now, not where it ended at
350
+ the read: a write through a run moves the live proxies (:func:`track_run`),
351
+ as clearing a run of text after a run of a break leaves an empty run that
352
+ ends where the break's run does. A read run holds the next run of its
353
+ read (``_next_read``), so the later ones stay live, and current, while it
354
+ is. None for a run proxy that is neither, which the SDK cannot tell from
355
+ the runs around it.
356
+ """
357
+ end = run._range[1]
358
+ records = _records_of(run)
359
+ own = getattr(run, "_run_record", None) or getattr(run, "_owner_record", None)
360
+ if own is not None and own in records:
361
+ return sum(1 for other in records[records.index(own) + 1 :] if other.range[1] == end)
362
+ read_seq = getattr(run, "_read_seq", None)
363
+ if read_seq is None:
364
+ return None
365
+ later = 0
366
+ following: Run | None = getattr(run, "_next_read", None)
367
+ while following is not None:
368
+ if following._range[1] == end:
369
+ later += 1
370
+ following = getattr(following, "_next_read", None)
371
+ return later + sum(1 for other in records if other.seq > read_seq and other.range[1] == end)
372
+
373
+
335
374
  def ends_last_at_its_end(run: "Run") -> bool:
336
375
  """True when no run ``add_run`` created after ``run`` ends where it does.
337
376
 
@@ -223,6 +223,10 @@ class Replace(Command):
223
223
  # …``), whose own properties docx-studio keeps for the new text; an older
224
224
  # docx-studio ignores it.
225
225
  whole_run: bool | None = None
226
+ # An empty run's identity among the runs at its place (``{"laterRuns": n}``,
227
+ # as ``Insert.run``), sent to a docx-studio reporting
228
+ # ``capabilities.runIdentity``.
229
+ run: dict[str, Any] | None = None
226
230
 
227
231
 
228
232
  @dataclass
@@ -233,13 +237,17 @@ class InsertLineBreak(Command):
233
237
  # ``True`` gives the break the formatting of the run it ends
234
238
  # (``Run.add_break``); an older docx-studio ignores it.
235
239
  inherit_marks: bool | None = None
236
- # ``"column"``: a column break (``Run.add_break(WD_BREAK.COLUMN)``), which
237
- # docx-studio writes after the paragraph's content, outside its
238
- # text-address space; an older docx-studio ignores it and inserts a line
239
- # break.
240
+ # ``"column"``: a column break (``Run.add_break(WD_BREAK.COLUMN)``),
241
+ # outside the paragraph's text-address space: with ``inline``, at the end
242
+ # of the run, in it; otherwise after the paragraph's content. An older
243
+ # docx-studio ignores it and inserts a line break.
240
244
  break_type: str | None = None
241
245
  # As ``Insert.run_edge``.
242
246
  run_edge: str | None = None
247
+ # ``True`` with ``break_type="column"``: the break at the end of the run,
248
+ # in it, as python-docx writes it. Sent only to a docx-studio reporting
249
+ # ``capabilities.inlineColumnBreak``; an older one ignores it.
250
+ inline: bool | None = None
243
251
 
244
252
 
245
253
  @dataclass
@@ -261,6 +269,10 @@ class FormatApply(Command):
261
269
  # (``run.bold = True``), which docx-studio keeps apart with their new
262
270
  # formatting; an older docx-studio ignores it.
263
271
  whole_run: bool | None = None
272
+ # The identity of an empty run that holds a page or column break
273
+ # (``{"laterRuns": n}``, as ``Insert.run``): its breaks take the
274
+ # formatting. Sent to a docx-studio reporting ``capabilities.runIdentity``.
275
+ run: dict[str, Any] | None = None
264
276
 
265
277
 
266
278
  @dataclass
@@ -725,6 +737,10 @@ class Info(Command):
725
737
  # ``docProps/core.xml``. An older docx-studio ignores the field, which
726
738
  # tells the SDK it has no ``SetCoreProperties``.
727
739
  include_core_properties: bool | None = None
740
+ # ``True`` also returns ``settings``: ``evenAndOddHeaders``, the
741
+ # document's ``w:evenAndOddHeaders`` in ``word/settings.xml``. An older
742
+ # docx-studio ignores the field and sends none.
743
+ include_settings: bool | None = None
728
744
 
729
745
 
730
746
  @dataclass
@@ -29,9 +29,12 @@ class Drawing:
29
29
  def has_picture(self) -> bool:
30
30
  """True when `drawing` contains an embedded picture.
31
31
 
32
- A drawing docx-studio reports in a run is always a picture.
32
+ As python-docx: False for a drawing whose graphic is not a picture (a
33
+ chart, a diagram, a group), which docx-studio reports with
34
+ ``hasPicture: false``. An older docx-studio reports none, and every
35
+ drawing it reports reads as a picture.
33
36
  """
34
- return True
37
+ return self._info.get("hasPicture") is not False
35
38
 
36
39
  @property
37
40
  def image(self) -> "Image":
@@ -44,6 +47,8 @@ class Drawing:
44
47
  from docx.image.image import Image
45
48
  from docx.shape import _strip_data_uri
46
49
 
50
+ if not self.has_picture:
51
+ raise ValueError("drawing does not contain a picture")
47
52
  image_id = self._info.get("imageId")
48
53
  if not isinstance(image_id, str) or not image_id:
49
54
  raise ValueError("drawing image cannot be read: docx-studio reported no id for it")
@@ -4,8 +4,9 @@ Most Word app settings are not surfaced by DOCX Studio, so this proxy is
4
4
  intentionally minimal. The fields that ARE exposed have one-to-one
5
5
  DOCX Studio semantics:
6
6
 
7
- * ``odd_and_even_pages_header_footer`` — toggles the document-level
8
- ``<w:evenAndOddHeaders/>`` flag via DOCX Studio 1.8.1's
7
+ * ``odd_and_even_pages_header_footer`` — reads the document-level
8
+ ``<w:evenAndOddHeaders/>`` flag from ``Info`` (``includeSettings``) and
9
+ toggles it via DOCX Studio 1.8.1's
9
10
  ``doc.sections.setOddEvenHeadersFooters`` (doc-level despite its
10
11
  namespace — see ``commands.SetSectionsOddEvenHeadersFooters``).
11
12
  * ``track_revisions`` — alias for :attr:`docx.document.Document.track_revisions`.
@@ -50,6 +51,15 @@ class Settings:
50
51
 
51
52
  @property
52
53
  def odd_and_even_pages_header_footer(self) -> bool:
54
+ """The document's ``w:evenAndOddHeaders`` in ``word/settings.xml``, as
55
+ python-docx reads it (False when absent or off). A docx-studio that
56
+ does not report it (``Info`` without ``settings``) gives the value this
57
+ proxy last set."""
58
+ info: object = run_sync(self._session.doc.info({"includeSettings": True}))
59
+ settings: object = info.get("settings") if isinstance(info, dict) else None
60
+ reported: object = settings.get("evenAndOddHeaders") if isinstance(settings, dict) else None
61
+ if isinstance(reported, bool):
62
+ return reported
53
63
  return self._odd_and_even_pages_header_footer
54
64
 
55
65
  @odd_and_even_pages_header_footer.setter
@@ -23,9 +23,11 @@ class PendingTableClearWarning(UserWarning):
23
23
  setter is asked to clear a property (``None`` assignment) that
24
24
  python-docx 1.x supports but DOCX Studio 1.8 has no clear-op for.
25
25
 
26
- Covers: ``Table.alignment / direction / autofit``,
26
+ Covers: ``Table.alignment / autofit``,
27
27
  ``_Row.height / height_rule``, ``_Column.width``,
28
- ``_Cell.width / vertical_alignment``. DOCX Studio's
28
+ ``_Cell.width / vertical_alignment``, and any ``Table.table_direction``
29
+ write to a docx-studio that does not report
30
+ ``capabilities.tableDirection`` (one that does writes None too). DOCX Studio's
29
31
  ``tables.set_layout`` / ``set_row_height`` / ``set_column_width``
30
32
  / ``set_cell_properties`` require explicit values — the wire
31
33
  can't represent the python-docx "revert to inherited" intent.
@@ -1241,36 +1243,48 @@ class Table:
1241
1243
  )
1242
1244
 
1243
1245
  @property
1244
- def direction(self) -> "WD_TABLE_DIRECTION | None":
1245
- from docx.enum.table import WD_TABLE_DIRECTION
1246
-
1246
+ def table_direction(self) -> "WD_TABLE_DIRECTION | None":
1247
+ """The table's ``w:bidiVisual`` as python-docx 1.2.0 reads it: ``True``
1248
+ (right to left), ``False`` (an explicit left to right) or None (none),
1249
+ the ``bool`` python-docx returns behind its ``WD_TABLE_DIRECTION`` hint
1250
+ (``True == WD_TABLE_DIRECTION.RTL``)."""
1247
1251
  info: object = run_sync(
1248
1252
  self._session.doc.tables.get_properties({"nodeId": self._fresh_node_id()}),
1249
1253
  )
1250
- if isinstance(info, dict):
1251
- return WD_TABLE_DIRECTION.from_docx_studio(info.get("direction"))
1254
+ direction: object = info.get("direction") if isinstance(info, dict) else None
1255
+ if direction == "rtl":
1256
+ return cast("WD_TABLE_DIRECTION", True)
1257
+ if direction == "ltr":
1258
+ return cast("WD_TABLE_DIRECTION", False)
1252
1259
  return None
1253
1260
 
1254
- @direction.setter
1255
- def direction(self, value: "WD_TABLE_DIRECTION | int | str | None") -> None:
1261
+ @table_direction.setter
1262
+ def table_direction(self, value: "WD_TABLE_DIRECTION | int | str | None") -> None:
1263
+ """As python-docx 1.2.0: RTL writes ``w:bidiVisual``, LTR writes
1264
+ ``w:bidiVisual w:val="0"`` and None removes it. A docx-studio that does
1265
+ not report ``capabilities.tableDirection`` drops the write, so the SDK
1266
+ sends none there and warns (``PendingTableClearWarning``)."""
1267
+ from docx._capabilities import server_takes
1268
+ from docx.commands import NULL
1256
1269
  from docx.enum.table import WD_TABLE_DIRECTION
1257
1270
 
1258
- if value is None:
1259
- _warn_table_clear("direction")
1271
+ # None goes on the wire as JSON null (``NULL``): a ``None`` field is left off it.
1272
+ wire: object = NULL if value is None else WD_TABLE_DIRECTION._wire(value, "Table.table_direction")
1273
+ if not server_takes(self._session, "tableDirection"):
1274
+ warnings.warn(
1275
+ "Table.table_direction was IGNORED: this DOCX Studio does not write a table's "
1276
+ "direction (w:bidiVisual); the table keeps its previous direction.",
1277
+ PendingTableClearWarning,
1278
+ stacklevel=2,
1279
+ )
1260
1280
  return
1261
- v: str = WD_TABLE_DIRECTION._wire(value, "Table.direction")
1262
- # DOCX Studio's setLayout takes ``tableDirection`` (not
1263
- # ``direction``). Same diagnostic as alignment above —
1264
- # setTableOptions silently swallowed the field.
1281
+ # DOCX Studio's setLayout takes ``tableDirection`` (not ``direction``).
1265
1282
  run_sync(
1266
1283
  self._session.doc.tables.set_layout(
1267
- {"nodeId": self._fresh_node_id(), "tableDirection": v},
1284
+ {"nodeId": self._fresh_node_id(), "tableDirection": wire},
1268
1285
  ),
1269
1286
  )
1270
1287
 
1271
- # python-docx aliases
1272
- table_direction = direction
1273
-
1274
1288
  @property
1275
1289
  def autofit(self) -> bool:
1276
1290
  info: object = run_sync(
@@ -171,13 +171,16 @@ class Hyperlink:
171
171
 
172
172
  @property
173
173
  def contains_page_break(self) -> bool:
174
- """True when the text of this hyperlink contains a hard page break.
174
+ """True when a rendered page break (a page Word's last layout began)
175
+ occurs in one of the hyperlink's runs, as python-docx 1.x reads it.
175
176
 
176
- Mirrors python-docx 1.x. Detection uses DOCX Studio's ``\\f`` form-
177
- feed sentinel inside any wrapped run's text (matching
178
- ``Run.contains_page_break`` / ``Paragraph.contains_page_break``).
177
+ docx-studio reads them in the runs (``renderedPageBreaks``); the
178
+ ``\\f`` sentinel is an older docx-studio's mark.
179
179
  """
180
180
  for run_data, _ in self._segments:
181
+ breaks = run_data.get("renderedPageBreaks")
182
+ if isinstance(breaks, list) and any(isinstance(brk, dict) for brk in breaks):
183
+ return True
181
184
  text = run_data.get("text", "")
182
185
  if isinstance(text, str) and "\f" in text:
183
186
  return True
@@ -53,15 +53,45 @@ def _warn_pagebreak_fragment(prop: str) -> None:
53
53
  )
54
54
 
55
55
 
56
+ class _ParagraphFragment:
57
+ """The part of a paragraph before or after one of its rendered page breaks.
58
+
59
+ python-docx returns a ``Paragraph`` divorced from the document body: a
60
+ copy of the paragraph cut at the break, whose changes the document never
61
+ sees. This one reads what text extraction asks of it, its ``text`` and
62
+ ``style``, and changes nothing.
63
+ """
64
+
65
+ __slots__ = ("_paragraph", "_text")
66
+
67
+ def __init__(self, *, paragraph: "Paragraph", text: str) -> None:
68
+ self._paragraph = paragraph
69
+ self._text = text
70
+
71
+ @property
72
+ def text(self) -> str:
73
+ """The fragment's text, as ``Paragraph.text`` reads it."""
74
+ return self._text
75
+
76
+ @property
77
+ def style(self):
78
+ """The paragraph's style: the fragment keeps the paragraph's properties."""
79
+ return self._paragraph.style
80
+
81
+ def __repr__(self) -> str:
82
+ return f"<_ParagraphFragment text={self._text!r}>"
83
+
84
+
56
85
  class RenderedPageBreak:
57
- """A hard page break inside a paragraph, as Word would render it.
86
+ """A page break Word's last layout put in a paragraph (``w:lastRenderedPageBreak``).
58
87
 
59
- Constructed by :meth:`Paragraph.rendered_page_breaks` and yielded
60
- by :meth:`Paragraph.iter_inner_content`; not intended for direct
61
- user instantiation.
88
+ Constructed by :meth:`Paragraph.rendered_page_breaks` and yielded by
89
+ :meth:`Run.iter_inner_content`; not intended for direct user
90
+ instantiation. ``info`` is the break as docx-studio reads it in its run
91
+ (``renderedPageBreaks``): its fragments' text, or no fragment.
62
92
  """
63
93
 
64
- __slots__ = ("_paragraph", "_offset", "_preceding_text")
94
+ __slots__ = ("_paragraph", "_offset", "_preceding_text", "_info")
65
95
 
66
96
  def __init__(
67
97
  self,
@@ -69,30 +99,47 @@ class RenderedPageBreak:
69
99
  paragraph: "Paragraph",
70
100
  offset: int = 0,
71
101
  preceding_text: str = "",
102
+ info: "dict | None" = None,
72
103
  ) -> None:
73
104
  self._paragraph: "Paragraph" = paragraph
74
105
  self._offset: int = offset
75
106
  self._preceding_text: str = preceding_text
107
+ self._info: "dict | None" = info
108
+
109
+ def _fragment(self, side: str) -> "_ParagraphFragment | None":
110
+ """python-docx's fragment on `side` (``preceding``/``following``) of this break."""
111
+ info = self._info
112
+ if info is None:
113
+ _warn_pagebreak_fragment(f"{side}_paragraph_fragment")
114
+ return None
115
+ if side not in info:
116
+ raise ValueError("only defined on first rendered page-break in paragraph")
117
+ text = info[side]
118
+ return (
119
+ None if text is None else _ParagraphFragment(paragraph=self._paragraph, text=str(text))
120
+ )
76
121
 
77
122
  # ---- python-docx canonical surface ----
78
123
  @property
79
- def preceding_paragraph_fragment(self) -> "Paragraph | None":
80
- """The portion of the paragraph that flowed onto the page
81
- *before* the break.
124
+ def preceding_paragraph_fragment(self) -> "_ParagraphFragment | None":
125
+ """The part of the paragraph before this break, as a paragraph.
82
126
 
83
- DOCX Studio's flat model doesn't preserve mid-paragraph fragments;
84
- returns ``None``. Use :attr:`preceding_paragraph_text` for the
85
- plain-text equivalent or the parent paragraph for full text.
127
+ None when no content precedes it (the break precedes all of the
128
+ paragraph's content). A break in a hyperlink puts the whole hyperlink
129
+ in this fragment. Raises ``ValueError`` for a break that is not the
130
+ paragraph's first, as python-docx does.
86
131
  """
87
- _warn_pagebreak_fragment("preceding_paragraph_fragment")
88
- return None
132
+ return self._fragment("preceding")
89
133
 
90
134
  @property
91
- def following_paragraph_fragment(self) -> "Paragraph | None":
92
- """The portion of the paragraph that flowed onto the page
93
- *after* the break. See :attr:`preceding_paragraph_fragment`."""
94
- _warn_pagebreak_fragment("following_paragraph_fragment")
95
- return None
135
+ def following_paragraph_fragment(self) -> "_ParagraphFragment | None":
136
+ """The part of the paragraph after this break, as a paragraph.
137
+
138
+ None when no content follows it. A break in a hyperlink leaves the
139
+ whole hyperlink out of this fragment. Raises ``ValueError`` for a
140
+ break that is not the paragraph's first, as python-docx does.
141
+ """
142
+ return self._fragment("following")
96
143
 
97
144
  # ---- athena-specific extensions (kept for compat) ----
98
145
  @property
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Any
9
9
  from docx._athena_extension import athena_extension
10
10
  from docx._batching import run_sync
11
11
  from docx._buffer import writes_unapplied
12
- from docx._run_order import forget_paragraph, register_run
12
+ from docx._run_order import forget_paragraph, read_stamp, register_run
13
13
  from docx._tracked import tracking
14
14
 
15
15
  #: The session attribute ``Paragraph.delete`` bumps, after which every
@@ -242,6 +242,30 @@ def _node_text(session: "Session", node_id: str, *, final: bool = False) -> str:
242
242
  return _extract_text(info, final=final)
243
243
 
244
244
 
245
+ def _rendered_page_break_reads(info: object) -> "list[tuple[dict, int]]":
246
+ """Each rendered page break docx-studio reads in the runs of the paragraph
247
+ whose node info is `info` (``renderedPageBreaks``), its links' included, in
248
+ order, with its offset in the paragraph's text-address space."""
249
+ if not isinstance(info, dict):
250
+ return []
251
+ node: object = info.get("node")
252
+ block: object = (node.get("paragraph") or node.get("heading")) if isinstance(node, dict) else None
253
+ inlines: object = block.get("inlines") if isinstance(block, dict) else None
254
+ reads: list[tuple[dict, int]] = []
255
+ offset = 0
256
+ for inline in inlines if isinstance(inlines, list) else []:
257
+ run: object = inline.get("run") if isinstance(inline, dict) else None
258
+ if not isinstance(run, dict):
259
+ continue
260
+ breaks: object = run.get("renderedPageBreaks")
261
+ for brk in breaks if isinstance(breaks, list) else []:
262
+ if isinstance(brk, dict):
263
+ reads.append((brk, offset + int(brk.get("offset", 0) or 0)))
264
+ text: object = run.get("text")
265
+ offset += len(text) if isinstance(text, str) else 0
266
+ return reads
267
+
268
+
245
269
  def _extract_text(info: object, *, final: bool = False) -> str:
246
270
  """Concatenate the text content of a paragraph, mirroring
247
271
  python-docx ``Paragraph.text`` semantics:
@@ -818,6 +842,13 @@ class Paragraph:
818
842
  # cache for free (avoids a follow-up ``get_node_by_id`` if the
819
843
  # caller does ``p.runs[...]; p.add_run(...)``).
820
844
  self._text_len = offset
845
+ # Each run holds the next one of this read: docx-studio tells it from
846
+ # the later ones that end where it does when content goes to it, by
847
+ # where they end then (``docx._run_order.later_runs_at_end``).
848
+ stamp = read_stamp()
849
+ for index, run_obj in enumerate(runs):
850
+ run_obj._next_read = runs[index + 1] if index + 1 < len(runs) else None
851
+ run_obj._read_seq = stamp
821
852
  return runs
822
853
 
823
854
  @property
@@ -1122,22 +1153,28 @@ class Paragraph:
1122
1153
 
1123
1154
  @property
1124
1155
  def contains_page_break(self) -> bool:
1125
- """python-docx 1.x: True if the paragraph contains a hard page break."""
1126
- return "\f" in self.text
1156
+ """python-docx 1.x: True when a rendered page break (a page Word's last
1157
+ layout began) occurs in one of the paragraph's runs or its links' runs."""
1158
+ info = self._node_info()
1159
+ return bool(_rendered_page_break_reads(info)) or "\f" in _extract_text(info, final=True)
1127
1160
 
1128
1161
  @property
1129
1162
  def rendered_page_breaks(self) -> "list[RenderedPageBreak]":
1130
- """Return a list of :class:`RenderedPageBreak` proxies for each
1131
- hard page break in this paragraph.
1132
-
1133
- python-docx 1.x exposes this for inspecting Word's rendered
1134
- page-break positions inside a paragraph. We surface a minimal
1135
- proxy with a ``preceding_paragraph_text`` property so the
1136
- common ``len(p.rendered_page_breaks)`` pattern works. The
1137
- underlying break is detected via the ``\\f`` sentinel in the
1138
- paragraph text.
1163
+ """python-docx 1.x: a :class:`RenderedPageBreak` for each page Word's
1164
+ last layout began in the paragraph's runs and its links' runs
1165
+ (``w:lastRenderedPageBreak``), in document order.
1166
+
1167
+ Each reads python-docx's fragments: the part of the paragraph before
1168
+ and after the break (``preceding_paragraph_fragment``,
1169
+ ``following_paragraph_fragment``), defined on the first break only.
1170
+ A paragraph from an older docx-studio marks its breaks with the
1171
+ ``\\f`` sentinel in its text instead.
1139
1172
  """
1140
- text = _extract_text(self._node_info())
1173
+ node_info = self._node_info()
1174
+ reads = _rendered_page_break_reads(node_info)
1175
+ if reads:
1176
+ return [RenderedPageBreak(paragraph=self, offset=offset, info=info) for info, offset in reads]
1177
+ text = _extract_text(node_info)
1141
1178
  if "\f" not in text:
1142
1179
  return []
1143
1180
  out: list[RenderedPageBreak] = []