athena-python-docx 0.36.0__tar.gz → 0.38.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 (491) hide show
  1. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/PKG-INFO +1 -1
  2. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/__init__.py +1 -1
  3. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/commands.py +11 -0
  4. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/table.py +12 -1
  5. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/run.py +109 -26
  6. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/pyproject.toml +1 -1
  7. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_drawing_image.py +56 -0
  8. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_enum_parity.py +14 -0
  9. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_ruby_reads_python_docx_parity.py +18 -2
  10. athena_python_docx-0.38.0/tests/test_run_break_inner_content.py +254 -0
  11. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_later_runs.py +91 -0
  12. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_mark_inheritance.py +35 -40
  13. athena_python_docx-0.38.0/tests/test_table_add_row_grid_row.py +65 -0
  14. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/uv.lock +1 -1
  15. athena_python_docx-0.36.0/tests/test_run_break_inner_content.py +0 -121
  16. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/.gitignore +0 -0
  17. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/AGENTS.md +0 -0
  18. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/CLAUDE.md +0 -0
  19. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/DOCX_EXEC_LAB.md +0 -0
  20. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/README.md +0 -0
  21. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_athena_extension.py +0 -0
  22. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_batching.py +0 -0
  23. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_buffer.py +0 -0
  24. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_capabilities.py +0 -0
  25. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_citations.py +0 -0
  26. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_execution.py +0 -0
  27. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_http.py +0 -0
  28. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_http_doc.py +0 -0
  29. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_image_utils.py +0 -0
  30. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_postproc.py +0 -0
  31. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_proxy.py +0 -0
  32. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_ptc.py +0 -0
  33. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_references.py +0 -0
  34. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_run_order.py +0 -0
  35. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_table_styles.py +0 -0
  36. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_timeouts.py +0 -0
  37. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_tracked.py +0 -0
  38. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/_xml_text.py +0 -0
  39. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/api.py +0 -0
  40. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/blkcntnr.py +0 -0
  41. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/bookmarks.py +0 -0
  42. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/charts.py +0 -0
  43. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/client.py +0 -0
  44. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/comments.py +0 -0
  45. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/document.py +0 -0
  46. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/drawing/__init__.py +0 -0
  47. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/__init__.py +0 -0
  48. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/base.py +0 -0
  49. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/dml.py +0 -0
  50. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/section.py +0 -0
  51. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/shape.py +0 -0
  52. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/style.py +0 -0
  53. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/table.py +0 -0
  54. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/enum/text.py +0 -0
  55. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/errors.py +0 -0
  56. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/exceptions.py +0 -0
  57. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/fields.py +0 -0
  58. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/footnotes.py +0 -0
  59. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/image/__init__.py +0 -0
  60. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/image/exceptions.py +0 -0
  61. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/image/image.py +0 -0
  62. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/math.py +0 -0
  63. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/opc/__init__.py +0 -0
  64. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/opc/coreprops.py +0 -0
  65. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/oxml/__init__.py +0 -0
  66. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/revisions.py +0 -0
  67. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/sdt.py +0 -0
  68. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/section.py +0 -0
  69. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/session.py +0 -0
  70. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/settings.py +0 -0
  71. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/shape.py +0 -0
  72. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/shared.py +0 -0
  73. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/styles/__init__.py +0 -0
  74. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/styles/_table.py +0 -0
  75. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/styles/latent.py +0 -0
  76. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/styles/style.py +0 -0
  77. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/styles/styles.py +0 -0
  78. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/__init__.py +0 -0
  79. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/font.py +0 -0
  80. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/hyperlink.py +0 -0
  81. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/pagebreak.py +0 -0
  82. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/paragraph.py +0 -0
  83. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/parfmt.py +0 -0
  84. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/text/tabstops.py +0 -0
  85. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/toc.py +0 -0
  86. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/docx/typing.py +0 -0
  87. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab.py +0 -0
  88. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  89. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  90. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_server.py +0 -0
  91. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/dump_wire_fixtures.py +0 -0
  92. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/release.sh +0 -0
  93. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/round_trip_smoke.py +0 -0
  94. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/smoke_test_block_not_found.py +0 -0
  95. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/scripts/validate_find_replace_asset.py +0 -0
  96. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/__init__.py +0 -0
  97. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/conftest.py +0 -0
  98. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/METHODOLOGY.md +0 -0
  99. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/README.md +0 -0
  100. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/__init__.py +0 -0
  101. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/__init__.py +0 -0
  102. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/agent_documents.py +0 -0
  103. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
  104. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
  105. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
  106. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
  107. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
  108. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/picture_runs.py +0 -0
  109. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
  110. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/return_types.py +0 -0
  111. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
  112. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
  113. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe_cases.py +0 -0
  114. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe_runner.py +0 -0
  115. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/auto_gen_cases.py +0 -0
  116. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/binary_round_trip.py +0 -0
  117. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/cases.py +0 -0
  118. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/complex_cases.py +0 -0
  119. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/coverage_report.py +0 -0
  120. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/extract.py +0 -0
  121. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/extreme_cases.py +0 -0
  122. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/fake_session.py +0 -0
  123. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/README.md +0 -0
  124. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  125. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  126. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  127. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  128. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  129. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/local_runner.py +0 -0
  130. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/mega_cases.py +0 -0
  131. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshot.py +0 -0
  132. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  133. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  134. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  135. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  136. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  137. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  138. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  139. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  140. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  141. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  142. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  143. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  144. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  145. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  146. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  147. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  148. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  149. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  150. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  151. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  152. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  153. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  154. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  155. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  156. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  157. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  158. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  159. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  160. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  161. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  162. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  163. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  164. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  165. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  166. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  167. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  168. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  169. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  170. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  171. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  172. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  173. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  174. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  175. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  176. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  177. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  178. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  179. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  180. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  181. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  182. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  183. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  184. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  185. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  186. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  187. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  188. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  189. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  190. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  191. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  192. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  193. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  194. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  195. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  196. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  197. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  198. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  199. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  200. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  201. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  202. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  203. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  204. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  205. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  206. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  207. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  208. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  209. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  210. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  211. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  212. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  213. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  214. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  215. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  216. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  217. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  218. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  219. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  220. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  221. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  222. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  223. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  224. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  225. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  226. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  227. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  228. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  229. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  230. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  231. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  232. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  233. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  234. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  235. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  236. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  237. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  238. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  239. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  240. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  241. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  242. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  243. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  244. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  245. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  246. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  247. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  248. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  249. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  250. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  251. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  252. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  253. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  254. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  255. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  256. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  257. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  258. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  259. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  260. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  261. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  262. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  263. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  264. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  265. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  266. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  267. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  268. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  269. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  270. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  271. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  272. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  273. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  274. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  275. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  276. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  277. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  278. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  279. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  280. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  281. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  282. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  283. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  284. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/ours_spec.json +0 -0
  285. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/parity_crawl.py +0 -0
  286. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/parity_diff.json +0 -0
  287. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/real_world_cases.py +0 -0
  288. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/round_trip_tests.py +0 -0
  289. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/stock_spec.json +0 -0
  290. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  291. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fixtures/field_reads.json +0 -0
  292. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fixtures/note_reference_reads.json +0 -0
  293. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fixtures/ruby_reads.json +0 -0
  294. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/fixtures/symbol_reads.json +0 -0
  295. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/__init__.py +0 -0
  296. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/baseline.json +0 -0
  297. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/fixture_scripts.py +0 -0
  298. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/reader.py +0 -0
  299. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/runner.py +0 -0
  300. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/sdk_driver.py +0 -0
  301. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/stock_driver.py +0 -0
  302. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/live/test_live_runner.py +0 -0
  303. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/README.md +0 -0
  304. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/__init__.py +0 -0
  305. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/baseline_gaps.json +0 -0
  306. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/compare.py +0 -0
  307. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/intentional_deviations.json +0 -0
  308. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/introspect.py +0 -0
  309. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  310. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/reports/gap_report.json +0 -0
  311. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/run_parity.py +0 -0
  312. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/snapshots/athena_latest.json +0 -0
  313. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  314. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/parity/test_parity_gap.py +0 -0
  315. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_add_section.py +0 -0
  316. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_add_section_extract_items.py +0 -0
  317. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_alignment_values.py +0 -0
  318. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  319. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_athena_extensions_contract.py +0 -0
  320. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_athena_extensions_registry.py +0 -0
  321. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_batch_chunking.py +0 -0
  322. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_batching_perf.py +0 -0
  323. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_battery_cases.py +0 -0
  324. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_block_not_found_error.py +0 -0
  325. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_buffer.py +0 -0
  326. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  327. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_add_table_not_supported.py +0 -0
  328. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_borders_spec.py +0 -0
  329. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_fastpath_runs.py +0 -0
  330. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  331. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  332. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_format_stash.py +0 -0
  333. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  334. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_run_guard.py +0 -0
  335. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_merge.py +0 -0
  336. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_nested_tables.py +0 -0
  337. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_paragraphs_listed.py +0 -0
  338. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  339. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_cell_text_replace_semantics.py +0 -0
  340. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_citations.py +0 -0
  341. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_collapsed_range_format.py +0 -0
  342. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_color_format_theme.py +0 -0
  343. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_command_dataclasses.py +0 -0
  344. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_commands.py +0 -0
  345. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_comment_paragraphs.py +0 -0
  346. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_comments.py +0 -0
  347. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_comments_first_read.py +0 -0
  348. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_content_control_value.py +0 -0
  349. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_core_properties.py +0 -0
  350. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_asset_id_property.py +0 -0
  351. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_clear.py +0 -0
  352. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_create.py +0 -0
  353. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_create_from_template.py +0 -0
  354. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_factory_validation.py +0 -0
  355. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_document_settings_session_open.py +0 -0
  356. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_docx_exec_lab.py +0 -0
  357. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_docx_exec_lab_server.py +0 -0
  358. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  359. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_empty_hyperlinks.py +0 -0
  360. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_execution_scope.py +0 -0
  361. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_export_docx_clean.py +0 -0
  362. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_export_rescue_anchors.py +0 -0
  363. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  364. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_field_refresh.py +0 -0
  365. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_field_runs.py +0 -0
  366. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_find_replace_session_open.py +0 -0
  367. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_flushed_write_failures.py +0 -0
  368. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_http_transport.py +0 -0
  369. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_hyperlink_coalescing.py +0 -0
  370. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_image_url_data_uri.py +0 -0
  371. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_inline_page_break.py +0 -0
  372. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_alt_text.py +0 -0
  373. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_size.py +0 -0
  374. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_type.py +0 -0
  375. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_inline_shapes_floating.py +0 -0
  376. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_insert_deferred.py +0 -0
  377. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_iter_inner_content.py +0 -0
  378. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_latent_style_writes.py +0 -0
  379. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_line_clear_break.py +0 -0
  380. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_list_styles.py +0 -0
  381. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_merged_cell_identity.py +0 -0
  382. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  383. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_merged_cells.py +0 -0
  384. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_missing_modules.py +0 -0
  385. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_nested_table_refused.py +0 -0
  386. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  387. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_oxml_shim.py +0 -0
  388. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_page_break.py +0 -0
  389. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_paragraph_delete.py +0 -0
  390. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_paragraph_indent_reads.py +0 -0
  391. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  392. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_paragraph_text_empty_run.py +0 -0
  393. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_paragraph_text_len_cache.py +0 -0
  394. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_parfmt_clears.py +0 -0
  395. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_parity_misc.py +0 -0
  396. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_parity_round2.py +0 -0
  397. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_partial_failure_cascade.py +0 -0
  398. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  399. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_phase_a_behavior.py +0 -0
  400. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_phase_b_headers_footers.py +0 -0
  401. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_phase_c_tables.py +0 -0
  402. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_positional_cell_id.py +0 -0
  403. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  404. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  405. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_postproc_ref_restore.py +0 -0
  406. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_pr19766_review_fixes.py +0 -0
  407. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_proxy_equality.py +0 -0
  408. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_ptc.py +0 -0
  409. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_python_docx_api_parity.py +0 -0
  410. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_read_run_ranges.py +0 -0
  411. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_rendered_page_breaks.py +0 -0
  412. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_repeated_node_read.py +0 -0
  413. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_restart_numbering.py +0 -0
  414. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_revisions.py +0 -0
  415. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_round_trip_smoke_script.py +0 -0
  416. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_add_picture_anchor.py +0 -0
  417. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_edges.py +0 -0
  418. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_formatting_wire.py +0 -0
  419. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_identity.py +0 -0
  420. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_page_number_blocks.py +0 -0
  421. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_table_style_objects.py +0 -0
  422. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_text_python_docx.py +0 -0
  423. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  424. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_run_unmodeled_toggles.py +0 -0
  425. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_sdk_reads_served.py +0 -0
  426. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_section_read_lengths.py +0 -0
  427. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  428. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_picture.py +0 -0
  429. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_run.py +0 -0
  430. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  431. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  432. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_comments_get.py +0 -0
  433. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_document_audit.py +0 -0
  434. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_document_element.py +0 -0
  435. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_enum_section.py +0 -0
  436. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_font_audit.py +0 -0
  437. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_header_footer.py +0 -0
  438. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_hyperlink.py +0 -0
  439. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_inline_shape.py +0 -0
  440. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  441. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_misc.py +0 -0
  442. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  443. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  444. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  445. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_parfmt.py +0 -0
  446. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  447. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_add_break.py +0 -0
  448. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  449. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_style.py +0 -0
  450. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  451. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_text.py +0 -0
  452. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_underline.py +0 -0
  453. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_audit.py +0 -0
  454. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  455. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_onoff.py +0 -0
  456. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_settings.py +0 -0
  457. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_shared_audit.py +0 -0
  458. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_style.py +0 -0
  459. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_styles.py +0 -0
  460. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_audit.py +0 -0
  461. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_cell.py +0 -0
  462. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  463. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_layout.py +0 -0
  464. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_smoke_integration.py +0 -0
  465. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_acceptance.py +0 -0
  466. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_delete.py +0 -0
  467. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_font.py +0 -0
  468. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_formatting_writes.py +0 -0
  469. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_metadata_writes.py +0 -0
  470. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_names.py +0 -0
  471. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_setters_contract.py +0 -0
  472. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_tab_stops.py +0 -0
  473. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_style_tab_stops_read.py +0 -0
  474. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  475. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_tab_stop_writes.py +0 -0
  476. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_anchors.py +0 -0
  477. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_clears.py +0 -0
  478. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_direction.py +0 -0
  479. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_read_reuse.py +0 -0
  480. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_set_cell_perf.py +0 -0
  481. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_table_style_id_resolution.py +0 -0
  482. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_temporarily_unavailable.py +0 -0
  483. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_text_control_characters.py +0 -0
  484. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_tracked_revisions_offsets.py +0 -0
  485. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_unmapped_alignment_reads.py +0 -0
  486. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_uv_lock_version.py +0 -0
  487. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  488. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_wire_contract.py +0 -0
  489. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_xml_attr_guard.py +0 -0
  490. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_xml_incompatible_text.py +0 -0
  491. {athena_python_docx-0.36.0 → athena_python_docx-0.38.0}/tests/test_zod_wire_contract.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.36.0
3
+ Version: 0.38.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.36.0"
9
+ __version__ = "0.38.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -565,10 +565,21 @@ class SetSectionLinkToPrevious(Command):
565
565
 
566
566
  @dataclass
567
567
  class TablesInsertRow(Command):
568
+ """``grid_row`` is python-docx's ``Table.add_row()``: the row goes after
569
+ the table's last one, with a cell for each grid column as wide as the
570
+ column, holding one empty paragraph, and nothing of the rows above.
571
+ ``copy_format_from`` is the Athena extension
572
+ ``Table.add_row(copy_format_from=k)``: the row goes after the table's
573
+ last one, formatted as Word's Insert Row below row ``k`` formats it.
574
+ Without either, the row is Word's Insert Row next to ``row_index``. A
575
+ docx-studio that predates a field ignores it."""
576
+
568
577
  node_id: str
569
578
  row_index: int
570
579
  position: str # "above" | "below"
571
580
  count: int = 1
581
+ grid_row: bool | None = None
582
+ copy_format_from: int | None = None
572
583
 
573
584
 
574
585
  @dataclass
@@ -1053,6 +1053,11 @@ class Table:
1053
1053
  }
1054
1054
  if source_index is not None:
1055
1055
  params["copyFormatFrom"] = source_index
1056
+ else:
1057
+ # python-docx's row: a cell for each grid column, as wide as the
1058
+ # column, and nothing of the last row (its height, grid skips,
1059
+ # header flag or cell formatting).
1060
+ params["gridRow"] = True
1056
1061
  run_sync(self._session.doc.tables.insert_row(params))
1057
1062
  # Keep the bounds-check cache current so the next ``cell()``
1058
1063
  # access still hits the fast path.
@@ -1235,7 +1240,13 @@ class Table:
1235
1240
  self._session.doc.tables.get_properties({"nodeId": self._fresh_node_id()}),
1236
1241
  )
1237
1242
  if isinstance(info, dict):
1238
- return WD_PARAGRAPH_ALIGNMENT.from_docx_studio(info.get("alignment"))
1243
+ raw: object = info.get("alignment")
1244
+ member = WD_PARAGRAPH_ALIGNMENT.from_docx_studio(raw)
1245
+ # python-docx reads `w:jc` through `from_xml`, which raises
1246
+ # ValueError for a value it has no member for (`start`, `end`).
1247
+ if member is None and isinstance(raw, str) and raw:
1248
+ return WD_PARAGRAPH_ALIGNMENT.from_xml(raw)
1249
+ return member
1239
1250
  return None
1240
1251
 
1241
1252
  @alignment.setter
@@ -454,11 +454,16 @@ class Run:
454
454
  formatting, so the formatting waits for content the run takes. So
455
455
  does a break the read says is no node of the paragraph
456
456
  (``breakApart``): one only its source run holds, a column-break
457
- block's, or the page break that opens the paragraph."""
457
+ block's, or the page break that opens the paragraph. The paragraph's
458
+ closing page break run (``closingBreak``) is formatted where the
459
+ docx-studio reports ``capabilities.closingBreakRunFormat``, which puts
460
+ its breaks back in the paragraph to take it."""
458
461
  if not self._is_collapsed_range or not self._holds_break() or tracking(self._session):
459
462
  return None
460
463
  if self._inline_snapshot.get("breakApart") is True:
461
- return None
464
+ closing = self._inline_snapshot.get("closingBreak") is True
465
+ if not closing or not server_takes(self._session, "closingBreakRunFormat"):
466
+ return None
462
467
  if self._inline_snapshot.get("break") == "column" and not server_takes(self._session, "inlineColumnBreak"):
463
468
  return None
464
469
  return self._later_runs()
@@ -468,14 +473,23 @@ class Run:
468
473
  and no text (a picture's run, ``drawing``), which a whole-run
469
474
  ``FormatApply`` of its collapsed range formats, untracked, on a
470
475
  docx-studio that reports ``capabilities.pictureRuns``: python-docx
471
- formats the run's ``w:r``, and docx-studio its picture. Else None."""
476
+ formats the run's ``w:r``, and docx-studio its picture. A legacy
477
+ picture's or object's run (``w:pict``, ``w:object``: ``drawing.legacy``
478
+ with its ``imageId``) too, on one that reports
479
+ ``capabilities.legacyPictureRuns``; not a preserved shape's (a
480
+ ``drawing.legacy`` with no ``imageId``), which no picture holds and the
481
+ format cannot reach. Else None."""
472
482
  if not self._is_collapsed_range or tracking(self._session):
473
483
  return None
474
484
  drawing = self._inline_snapshot.get("drawing")
475
- if not isinstance(drawing, dict) or drawing.get("legacy") is True:
485
+ if not isinstance(drawing, dict):
476
486
  return None
477
487
  if not server_takes(self._session, "pictureRuns"):
478
488
  return None
489
+ if drawing.get("legacy") is True and (
490
+ not drawing.get("imageId") or not server_takes(self._session, "legacyPictureRuns")
491
+ ):
492
+ return None
479
493
  return self._later_runs()
480
494
 
481
495
  def _empty_run_identity(self) -> int | None:
@@ -866,6 +880,15 @@ class Run:
866
880
  items: list[tuple[int, float, dict, bool]] = [
867
881
  (offset, index, info, True) for index, (offset, info) in enumerate(pictures)
868
882
  ]
883
+ # python-docx yields "" for each stretch of the run that the pictures
884
+ # bound and that holds a page or column break and no text, by how
885
+ # many pictures come before it (``emptyTextAfterPictures``). From a
886
+ # docx-studio that does not say, a run of a break and pictures and
887
+ # no text yields the break's "" before them.
888
+ empty_after = self._empty_text_after_pictures()
889
+ if empty_after is None:
890
+ breaks = not raw and self._inline_snapshot.get("break") in ("page", "column")
891
+ empty_after = {0} if breaks else set()
869
892
  rendered = self._rendered_page_breaks()
870
893
  for info in rendered:
871
894
  offset = int(info.get("offset", 0) or 0)
@@ -875,15 +898,23 @@ class Run:
875
898
  items.append((offset, after - 0.5, info, False))
876
899
  items.sort(key=lambda item: (item[0], item[1]))
877
900
  cut = 0
901
+ pictures_yielded = 0
878
902
  for offset, _order, info, is_picture in items:
879
903
  at = min(max(offset, cut), len(raw))
880
904
  if _word_text(raw[cut:at], font):
881
905
  yield _word_text(raw[cut:at], font)
882
906
  if not is_picture:
883
907
  yield RenderedPageBreak(paragraph=self._page_break_paragraph(), offset=self._range[0] + at, info=info)
884
- elif info.get("legacy") is not True:
885
- yield Drawing(session=self._session, info=info)
908
+ else:
909
+ if pictures_yielded in empty_after:
910
+ yield ""
911
+ empty_after.discard(pictures_yielded)
912
+ if info.get("legacy") is not True:
913
+ yield Drawing(session=self._session, info=info)
914
+ pictures_yielded += 1
886
915
  cut = at
916
+ if pictures_yielded in empty_after:
917
+ yield ""
887
918
  if _word_text(raw[cut:], font):
888
919
  yield _word_text(raw[cut:], font)
889
920
  return
@@ -1063,11 +1094,14 @@ class Run:
1063
1094
  # server keeps its own properties (``w:bCs``, an off toggle) for the
1064
1095
  # new text, as python-docx keeps the run's ``w:rPr``. A docx-studio
1065
1096
  # from before the field ignores it.
1066
- run_sync(
1067
- self._session.doc.replace(
1068
- {"target": self._text_range, "text": value, "wholeRun": True},
1069
- ),
1070
- )
1097
+ command: dict = {"target": self._text_range, "text": value, "wholeRun": True}
1098
+ later = later_runs_at_end(self)
1099
+ if later and server_takes(self._session, "runIdentity"):
1100
+ # A run after this one ends where it does (an empty run, a text
1101
+ # box's or a SmartArt drawing's): docx-studio tells this run's
1102
+ # record from its by the run's identity, and keeps both.
1103
+ command["run"] = {"laterRuns": later}
1104
+ run_sync(self._session.doc.replace(command))
1071
1105
  if not tracked:
1072
1106
  new_end: int = self._range[0] + len(value)
1073
1107
  self._range = (self._range[0], new_end)
@@ -1237,6 +1271,34 @@ class Run:
1237
1271
  snapshot.setdefault("break", kind)
1238
1272
  if held:
1239
1273
  snapshot.pop("breakApart", None)
1274
+ self._note_empty_text_after_pictures()
1275
+
1276
+ def _note_empty_text_after_pictures(self) -> None:
1277
+ """This run took a page or column break at its end, after its pictures:
1278
+ python-docx yields its ``""`` after the last of them while no text
1279
+ follows it there (``emptyTextAfterPictures``). A picture's run
1280
+ (``drawing``) holds its picture among its pictures (``pictures``) then."""
1281
+ snapshot = self._inline_snapshot
1282
+ alone = snapshot.get("drawing")
1283
+ pictures = self._pictures() or ([(0, alone)] if isinstance(alone, dict) else [])
1284
+ if not pictures or self._raw_text()[pictures[-1][0]:]:
1285
+ return
1286
+ if isinstance(alone, dict):
1287
+ snapshot.pop("drawing")
1288
+ snapshot["pictures"] = [{"offset": 0, "drawing": alone}]
1289
+ places = snapshot.setdefault("emptyTextAfterPictures", [])
1290
+ if isinstance(places, list) and len(pictures) not in places:
1291
+ places.append(len(pictures))
1292
+
1293
+ def _empty_text_after_pictures(self) -> "set[int] | None":
1294
+ """Where :meth:`iter_inner_content` yields ``""`` among this run's
1295
+ pictures (``emptyTextAfterPictures``): each stretch the pictures bound
1296
+ that holds a page or column break and no text, by how many pictures
1297
+ come before it. None when the read does not say."""
1298
+ places: object = self._inline_snapshot.get("emptyTextAfterPictures")
1299
+ if not isinstance(places, list):
1300
+ return None
1301
+ return {p for p in places if isinstance(p, int) and not isinstance(p, bool)}
1240
1302
 
1241
1303
  def add_break(self, break_type: "WD_BREAK" = WD_BREAK.LINE) -> None:
1242
1304
  """Insert a break at the end of the run.
@@ -1518,17 +1580,25 @@ class Run:
1518
1580
  def _hold_picture(self, drawing: dict) -> None:
1519
1581
  """This run took the picture ``drawing`` at its end (``run.add_picture``),
1520
1582
  as the next read gives it: a run of a picture alone as a picture's run
1521
- (``drawing``), else among its pictures (``pictures``) where its text ends."""
1583
+ (``drawing``), else among its pictures (``pictures``) where its text ends.
1584
+ A run of a page or column break and no text holds it among its
1585
+ pictures, after the break's ``""`` (``emptyTextAfterPictures``)."""
1522
1586
  snapshot = self._inline_snapshot
1523
1587
  held = self._pictures()
1524
1588
  alone = snapshot.get("drawing")
1525
- if not held and not self._raw_text() and not isinstance(alone, dict):
1589
+ raw = self._raw_text()
1590
+ break_first = not held and not raw and not isinstance(alone, dict) and snapshot.get("break") in ("page", "column")
1591
+ if not held and not raw and not isinstance(alone, dict) and not break_first:
1526
1592
  snapshot["drawing"] = drawing
1527
1593
  return
1528
1594
  if isinstance(alone, dict):
1529
1595
  held = [(0, snapshot.pop("drawing"))]
1530
- held.append((len(self._raw_text()), drawing))
1596
+ held.append((len(raw), drawing))
1531
1597
  snapshot["pictures"] = [{"offset": offset, "drawing": info} for offset, info in held]
1598
+ if break_first:
1599
+ places = snapshot.setdefault("emptyTextAfterPictures", [])
1600
+ if isinstance(places, list) and 0 not in places:
1601
+ places.append(0)
1532
1602
 
1533
1603
  @athena_extension(
1534
1604
  issue=498,
@@ -1879,15 +1949,19 @@ class Run:
1879
1949
 
1880
1950
  # ---- formatting helpers ----
1881
1951
  def _formatting_from_snapshot(self) -> dict:
1882
- """This run's formatting as a ``format.apply`` inline bag.
1952
+ """This run's own formatting as a ``format.apply`` inline bag: the
1953
+ values the run sets itself, an explicit off toggle (``w:b w:val="0"``)
1954
+ included, as python-docx keeps the run's ``w:rPr`` for its next text.
1883
1955
 
1884
1956
  Only for a snapshot with every formatting key that is set
1885
- (``_marks_known``): a toggle that the snapshot does not hold is sent
1886
- as ``False``, so the new text does not take a toggle from the
1887
- paragraph's default run formatting either.
1957
+ (``_marks_known``). A toggle the run does not set stays unset: the new
1958
+ text, which docx-studio gives no formatting of its own (no
1959
+ ``inheritMarks``), shows what the styles give it, as python-docx's
1960
+ does. Sending it as ``False`` wrote an explicit off, so text written
1961
+ into an emptied heading run lost the heading's bold.
1888
1962
  """
1889
1963
  snapshot = self._inline_snapshot
1890
- out: dict = {key: False for key in _RUN_MARK_TOGGLES}
1964
+ out: dict = {}
1891
1965
  for key in _RUN_MARK_KEYS:
1892
1966
  value = snapshot.get(key)
1893
1967
  if value is not None:
@@ -2002,6 +2076,9 @@ class Run:
2002
2076
  )
2003
2077
  # Its break or picture holds the formatting now, which what it takes next continues.
2004
2078
  self._fresh = False
2079
+ # A closing page break run's breaks are the paragraph's now, as the next read gives them.
2080
+ if self._inline_snapshot.pop("closingBreak", None) is True:
2081
+ self._inline_snapshot.pop("breakApart", None)
2005
2082
  return
2006
2083
  if self._is_collapsed_range:
2007
2084
  pending = getattr(self, "_pending_inline", None)
@@ -2016,17 +2093,23 @@ class Run:
2016
2093
  {"target": self._text_range, "inline": kwargs, "wholeRun": True},
2017
2094
  ),
2018
2095
  )
2019
- self._edited_ruby()
2096
+ self._edited_ruby(formatted=True)
2020
2097
 
2021
- def _edited_ruby(self) -> None:
2098
+ def _edited_ruby(self, *, formatted: bool = False) -> None:
2022
2099
  """This run's text or formatting changed: docx-studio writes the base
2023
2100
  text of each ruby it held as text from then on (it keeps no guide
2024
- through an edit), so the run reads it as text. It writes the run's
2025
- symbol-block characters as a ``w:sym`` in the font the run owns too,
2026
- so a read's null ``symbolFont`` (a source ``w:t``'s characters) gives
2027
- way to the run's font (``_symbol_font``)."""
2101
+ through an edit), so the run reads it as text. A docx-studio that
2102
+ reports ``capabilities.rubyThroughFormat`` keeps the ruby through a
2103
+ whole-run format (``formatted``), as python-docx keeps the run's
2104
+ ``w:ruby``, so the run goes on reading it as the ruby's. It writes the
2105
+ run's symbol-block characters as a ``w:sym`` in the font the run owns
2106
+ too, so a read's null ``symbolFont`` (a source ``w:t``'s characters)
2107
+ gives way to the run's font (``_symbol_font``)."""
2028
2108
  snapshot = getattr(self, "_inline_snapshot", {})
2029
- snapshot.pop("ruby", None)
2109
+ if "ruby" in snapshot and not (
2110
+ formatted and server_takes(getattr(self, "_session", None), "rubyThroughFormat")
2111
+ ):
2112
+ snapshot.pop("ruby", None)
2030
2113
  if "symbolFont" in snapshot and snapshot["symbolFont"] is None:
2031
2114
  snapshot.pop("symbolFont")
2032
2115
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.36.0"
7
+ version = "0.38.0"
8
8
  description = "Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -466,6 +466,62 @@ class TestRunsHoldingPictures:
466
466
  assert formats == []
467
467
  assert picture_run._pending_inline == {"italic": True}
468
468
 
469
+ @pytest.mark.parametrize(("capability", "sent"), [(True, True), (False, False)])
470
+ def test_formatting_a_legacy_objects_run_formats_it_where_docx_studio_formats_them(
471
+ self, mock_session: Any, fake_sd_methods: Any, capability: bool, sent: bool
472
+ ) -> None:
473
+ """``p.runs[1].italic = True`` of an embedded object's run
474
+ (``<w:r><w:object>…</w:object></w:r>``, read as ``drawing.legacy``):
475
+ python-docx formats its ``w:r``. A docx-studio without
476
+ ``capabilities.legacyPictureRuns`` keeps the formatting for the text the
477
+ run takes, as before."""
478
+ fake_sd_methods.scripted_returns["info"] = {
479
+ "capabilities": {"pictureRuns": True, "legacyPictureRuns": capability, "runIdentity": True}
480
+ }
481
+ paragraph = _paragraph(
482
+ mock_session,
483
+ fake_sd_methods,
484
+ [{"run": {"text": "The figures "}}, {"drawing": {"imageId": "p1:0:aa", "legacy": True}}, {"run": {"text": " sit here."}}],
485
+ )
486
+ object_run = paragraph.runs[1]
487
+
488
+ object_run.italic = True
489
+
490
+ formats = [params for op, params in fake_sd_methods.calls if op == "format.apply"]
491
+ if sent:
492
+ assert formats == [
493
+ {
494
+ "target": {"kind": "text", "blockId": "p1", "range": {"start": 12, "end": 12}},
495
+ "inline": {"italic": True},
496
+ "wholeRun": True,
497
+ "run": {"laterRuns": 0},
498
+ }
499
+ ]
500
+ else:
501
+ assert formats == []
502
+ assert object_run._pending_inline == {"italic": True}
503
+
504
+ def test_formatting_a_preserved_shapes_run_stays_pending(self, mock_session: Any, fake_sd_methods: Any) -> None:
505
+ """A shape docx-studio keeps as it was (``mc:AlternateContent``) reads
506
+ as ``drawing.legacy`` with no ``imageId``: no picture holds it, so a
507
+ format of its run would reply ``formatted: false``. Its formatting stays
508
+ pending, as before, also on a docx-studio that reports
509
+ ``legacyPictureRuns``."""
510
+ fake_sd_methods.scripted_returns["info"] = {
511
+ "capabilities": {"pictureRuns": True, "legacyPictureRuns": True, "runIdentity": True}
512
+ }
513
+ paragraph = _paragraph(
514
+ mock_session,
515
+ fake_sd_methods,
516
+ [{"run": {"text": "Before "}}, {"drawing": {"imageId": None, "legacy": True}}, {"run": {"text": " after"}}],
517
+ )
518
+ shape_run = paragraph.runs[1]
519
+
520
+ shape_run.italic = True
521
+
522
+ assert [params for op, params in fake_sd_methods.calls if op == "format.apply"] == []
523
+ assert shape_run._pending_inline == {"italic": True}
524
+
469
525
  def test_a_pictures_run_reads_its_formatting(self, mock_session: Any, fake_sd_methods: Any) -> None:
470
526
  """python-docx reads a picture's run's ``w:rPr``: docx-studio reads its
471
527
  formatting on the picture's inline beside its drawing."""
@@ -386,6 +386,20 @@ def test_getters_return_int_members(mock_session: Any, fake_sd_methods: Any) ->
386
386
  assert table.table_direction is True and table.table_direction == WD_TABLE_DIRECTION.RTL
387
387
 
388
388
 
389
+ @pytest.mark.parametrize("jc", ["start", "end"])
390
+ def test_a_table_of_start_or_end_justification_raises_as_python_docx_reads_it(
391
+ mock_session: Any, fake_sd_methods: Any, jc: str
392
+ ) -> None:
393
+ """python-docx 1.2.0 reads a table's ``w:jc`` through the paragraph
394
+ ``CT_Jc``, whose enum has no member for ``start`` or ``end``."""
395
+ from docx.table import Table
396
+
397
+ fake_sd_methods.scripted_returns["tables.get_properties"] = {"alignment": jc}
398
+ table = Table(session=mock_session, node_id="tbl-1")
399
+ with pytest.raises(ValueError, match=f"WD_PARAGRAPH_ALIGNMENT has no XML mapping for '{jc}'"):
400
+ _ = table.alignment
401
+
402
+
389
403
  @pytest.mark.parametrize(
390
404
  "assign",
391
405
  [
@@ -13,8 +13,10 @@ is installed.
13
13
 
14
14
  docx-studio keeps the base text in its run's text, the room it takes in the
15
15
  text-address space, and gives its spans as ``ruby``: edits addressed after the
16
- ruby land after it. Once the run's text or formatting changes, docx-studio
17
- writes the base text as text, and the run reads it so.
16
+ ruby land after it. Once the run's text changes, docx-studio writes the base
17
+ text as text, and the run reads it so; so does a format of the run, but on a
18
+ docx-studio that reports ``rubyThroughFormat``, which keeps the ruby through it
19
+ as python-docx does.
18
20
  """
19
21
 
20
22
  from __future__ import annotations
@@ -190,3 +192,17 @@ def test_an_edit_of_the_rubys_run_reads_its_base_text_as_text(
190
192
 
191
193
  assert _writes(fake_sd_methods)
192
194
  assert "ruby" not in ruby._inline_snapshot
195
+
196
+
197
+ def test_a_format_of_the_rubys_run_keeps_its_ruby_where_docx_studio_keeps_it(
198
+ mock_session: Any, fake_sd_methods: Any
199
+ ) -> None:
200
+ # A docx-studio that reports `rubyThroughFormat` keeps the run's `w:ruby`
201
+ # through a whole-run format, as python-docx keeps it: the run still reads "".
202
+ fake_sd_methods.scripted_returns["info"] = {"capabilities": {"rubyThroughFormat": True}}
203
+ ruby = _body(mock_session, fake_sd_methods).runs[1]
204
+
205
+ ruby.bold = True
206
+
207
+ assert ruby._inline_snapshot.get("ruby") == [[0, 1]]
208
+ assert ruby.text == ""