athena-python-docx 0.24.0__tar.gz → 0.25.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 (387) hide show
  1. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/AGENTS.md +44 -8
  2. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_buffer.py +17 -0
  5. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_http_doc.py +134 -8
  6. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_postproc.py +1 -1
  7. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_timeouts.py +2 -0
  8. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/client.py +16 -0
  9. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/commands.py +22 -4
  10. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/document.py +236 -43
  11. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/errors.py +38 -15
  12. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/section.py +172 -122
  13. athena_python_docx-0.25.0/docx/styles/__init__.py +38 -0
  14. athena_python_docx-0.25.0/docx/styles/_table.py +303 -0
  15. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/styles/style.py +5 -1
  16. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/styles/styles.py +88 -34
  17. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/table.py +188 -60
  18. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/paragraph.py +89 -45
  19. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/run.py +145 -6
  20. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/pyproject.toml +1 -1
  21. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/fake_session.py +15 -1
  22. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +1 -0
  23. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/15_run_add_break_page.json +6 -0
  24. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/29_section_headers_linked.json +7 -0
  25. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +1 -0
  26. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/35_full_report.json +1 -0
  27. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/48_font_color_round_trip.json +5 -0
  28. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/49_resume_layout.json +1 -0
  29. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +1 -0
  30. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +3 -1
  31. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/71_academic_paper.json +1 -0
  32. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/72_legal_contract.json +1 -0
  33. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +1 -0
  34. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +5 -0
  35. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +1 -0
  36. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +2 -2
  37. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/85_header_footer_access.json +7 -0
  38. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +1 -1
  39. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/47_font_size_round_trip.json → athena_python_docx-0.25.0/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +1 -1
  40. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +7 -0
  41. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +1 -0
  42. athena_python_docx-0.25.0/tests/fidelity/op_snapshots/98_style_contains_check.json +6 -0
  43. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +1 -0
  44. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +1 -0
  45. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +2 -1
  46. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +13 -6
  47. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +1 -0
  48. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +2 -2
  49. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +1 -0
  50. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +1 -0
  51. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +1 -0
  52. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +1 -0
  53. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +1 -0
  54. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +1 -0
  55. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +2 -1
  56. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +1 -0
  57. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +2 -1
  58. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +1 -0
  59. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw11_header_text.json +2 -0
  60. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +4 -0
  61. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +4 -0
  62. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +1 -0
  63. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/intentional_deviations.json +0 -3
  64. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_athena_extensions_registry.py +3 -0
  65. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_block_not_found_error.py +29 -0
  66. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_buffer.py +43 -6
  67. athena_python_docx-0.25.0/tests/test_cell_borders_spec.py +100 -0
  68. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_inner_format_stash.py +4 -2
  69. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_commands.py +19 -7
  70. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_http_transport.py +10 -10
  71. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_iter_inner_content.py +3 -3
  72. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_list_styles.py +8 -3
  73. athena_python_docx-0.25.0/tests/test_page_break.py +49 -0
  74. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_parity_misc.py +2 -2
  75. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_parity_round2.py +19 -5
  76. athena_python_docx-0.25.0/tests/test_pdf_export_and_page_renders.py +321 -0
  77. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_phase_a_behavior.py +2 -1
  78. athena_python_docx-0.25.0/tests/test_phase_b_headers_footers.py +471 -0
  79. athena_python_docx-0.25.0/tests/test_run_mark_inheritance.py +414 -0
  80. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_paragraph_style_strict.py +2 -1
  81. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_add_break.py +7 -7
  82. athena_python_docx-0.25.0/tests/test_style_names.py +272 -0
  83. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_wire_contract.py +17 -2
  84. athena_python_docx-0.24.0/docx/styles/__init__.py +0 -1
  85. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -5
  86. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -6
  87. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -3
  88. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -6
  89. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -5
  90. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -8
  91. athena_python_docx-0.24.0/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -6
  92. athena_python_docx-0.24.0/tests/test_phase_b_headers_footers.py +0 -281
  93. athena_python_docx-0.24.0/tests/test_run_mark_inheritance.py +0 -164
  94. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/.gitignore +0 -0
  95. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/CLAUDE.md +0 -0
  96. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/DOCX_EXEC_LAB.md +0 -0
  97. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/README.md +0 -0
  98. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_athena_extension.py +0 -0
  99. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_batching.py +0 -0
  100. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_citations.py +0 -0
  101. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_execution.py +0 -0
  102. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_http.py +0 -0
  103. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_image_utils.py +0 -0
  104. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_ptc.py +0 -0
  105. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_references.py +0 -0
  106. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_run_order.py +0 -0
  107. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/_table_styles.py +0 -0
  108. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/api.py +0 -0
  109. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/bookmarks.py +0 -0
  110. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/charts.py +0 -0
  111. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/comments.py +0 -0
  112. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/__init__.py +0 -0
  113. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/section.py +0 -0
  114. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/shape.py +0 -0
  115. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/style.py +0 -0
  116. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/table.py +0 -0
  117. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/enum/text.py +0 -0
  118. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/exceptions.py +0 -0
  119. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/fields.py +0 -0
  120. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/footnotes.py +0 -0
  121. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/math.py +0 -0
  122. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/opc/__init__.py +0 -0
  123. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/opc/coreprops.py +0 -0
  124. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/oxml/__init__.py +0 -0
  125. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/revisions.py +0 -0
  126. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/sdt.py +0 -0
  127. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/session.py +0 -0
  128. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/settings.py +0 -0
  129. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/shape.py +0 -0
  130. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/shared.py +0 -0
  131. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/__init__.py +0 -0
  132. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/font.py +0 -0
  133. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/hyperlink.py +0 -0
  134. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/pagebreak.py +0 -0
  135. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/parfmt.py +0 -0
  136. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/text/tabstops.py +0 -0
  137. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/toc.py +0 -0
  138. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/docx/typing.py +0 -0
  139. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/docx_exec_lab.py +0 -0
  140. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  141. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  142. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/docx_exec_lab_server.py +0 -0
  143. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/dump_wire_fixtures.py +0 -0
  144. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/release.sh +0 -0
  145. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/round_trip_smoke.py +0 -0
  146. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/smoke_test_block_not_found.py +0 -0
  147. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/scripts/validate_find_replace_asset.py +0 -0
  148. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/__init__.py +0 -0
  149. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/conftest.py +0 -0
  150. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/METHODOLOGY.md +0 -0
  151. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/README.md +0 -0
  152. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/__init__.py +0 -0
  153. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/ab_probe_cases.py +0 -0
  154. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/ab_probe_runner.py +0 -0
  155. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/auto_gen_cases.py +0 -0
  156. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/binary_round_trip.py +0 -0
  157. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/cases.py +0 -0
  158. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/complex_cases.py +0 -0
  159. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/coverage_report.py +0 -0
  160. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/extract.py +0 -0
  161. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/extreme_cases.py +0 -0
  162. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/README.md +0 -0
  163. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  164. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  165. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  166. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  167. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  168. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/local_runner.py +0 -0
  169. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/mega_cases.py +0 -0
  170. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshot.py +0 -0
  171. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  172. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  173. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  174. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  175. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  176. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  177. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  178. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  179. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  180. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  181. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  182. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  183. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  184. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  185. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  186. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  187. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  188. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  189. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  190. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  191. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  192. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  193. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  194. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  195. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  196. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  197. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  198. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  199. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  200. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  201. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  202. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  203. /athena_python_docx-0.24.0/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json → /athena_python_docx-0.25.0/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  204. /athena_python_docx-0.24.0/tests/fidelity/op_snapshots/98_style_contains_check.json → /athena_python_docx-0.25.0/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  205. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  206. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  207. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  208. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  209. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  210. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  211. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  212. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  213. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  214. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  215. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  216. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  217. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  218. /athena_python_docx-0.24.0/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json → /athena_python_docx-0.25.0/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  219. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  220. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  221. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  222. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  223. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  224. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  225. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  226. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  227. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  228. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  229. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  230. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  231. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  232. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  233. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  234. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  235. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  236. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  237. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  238. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  239. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  240. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  241. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  242. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  243. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  244. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  245. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  246. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  247. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  248. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  249. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  250. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  251. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  252. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  253. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  254. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  255. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  256. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  257. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  258. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  259. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  260. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  261. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  262. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  263. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  264. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  265. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  266. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  267. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  268. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  269. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  270. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  271. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  272. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  273. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  274. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  275. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  276. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  277. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/ours_spec.json +0 -0
  278. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/parity_crawl.py +0 -0
  279. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/parity_diff.json +0 -0
  280. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/real_world_cases.py +0 -0
  281. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/round_trip_tests.py +0 -0
  282. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/stock_spec.json +0 -0
  283. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  284. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/README.md +0 -0
  285. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/__init__.py +0 -0
  286. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/baseline_gaps.json +0 -0
  287. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/compare.py +0 -0
  288. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/introspect.py +0 -0
  289. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  290. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/reports/gap_report.json +0 -0
  291. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/run_parity.py +0 -0
  292. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/snapshots/athena_latest.json +0 -0
  293. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  294. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/parity/test_parity_gap.py +0 -0
  295. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_add_section_extract_items.py +0 -0
  296. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  297. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_athena_extensions_contract.py +0 -0
  298. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_batching_perf.py +0 -0
  299. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  300. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_add_table_not_supported.py +0 -0
  301. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_fastpath_runs.py +0 -0
  302. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  303. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  304. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  305. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_inner_run_guard.py +0 -0
  306. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  307. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_cell_text_replace_semantics.py +0 -0
  308. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_citations.py +0 -0
  309. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_collapsed_range_format.py +0 -0
  310. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_command_dataclasses.py +0 -0
  311. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_comments.py +0 -0
  312. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_document_asset_id_property.py +0 -0
  313. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_document_clear.py +0 -0
  314. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_document_create.py +0 -0
  315. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_document_create_from_template.py +0 -0
  316. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_document_factory_validation.py +0 -0
  317. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_docx_exec_lab.py +0 -0
  318. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_docx_exec_lab_server.py +0 -0
  319. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  320. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_execution_scope.py +0 -0
  321. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_find_replace_session_open.py +0 -0
  322. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_hyperlink_coalescing.py +0 -0
  323. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_image_url_data_uri.py +0 -0
  324. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_inline_shape_alt_text.py +0 -0
  325. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_insert_deferred.py +0 -0
  326. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  327. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_merged_cells.py +0 -0
  328. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_oxml_shim.py +0 -0
  329. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_paragraph_text_len_cache.py +0 -0
  330. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_partial_failure_cascade.py +0 -0
  331. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_phase_c_tables.py +0 -0
  332. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_positional_cell_id.py +0 -0
  333. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  334. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  335. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_postproc_ref_restore.py +0 -0
  336. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_pr19766_review_fixes.py +0 -0
  337. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_ptc.py +0 -0
  338. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_python_docx_api_parity.py +0 -0
  339. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_revisions.py +0 -0
  340. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_run_add_picture_anchor.py +0 -0
  341. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_run_identity.py +0 -0
  342. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  343. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_add_picture.py +0 -0
  344. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_add_run.py +0 -0
  345. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  346. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  347. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_comments_get.py +0 -0
  348. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_document_audit.py +0 -0
  349. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_document_element.py +0 -0
  350. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_enum_section.py +0 -0
  351. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_font_audit.py +0 -0
  352. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_header_footer.py +0 -0
  353. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_hyperlink.py +0 -0
  354. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_inline_shape.py +0 -0
  355. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  356. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_misc.py +0 -0
  357. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  358. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  359. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_parfmt.py +0 -0
  360. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  361. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  362. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_style.py +0 -0
  363. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  364. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_text.py +0 -0
  365. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_run_underline.py +0 -0
  366. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_section_audit.py +0 -0
  367. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  368. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_section_onoff.py +0 -0
  369. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_settings.py +0 -0
  370. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_shared_audit.py +0 -0
  371. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_style.py +0 -0
  372. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_styles.py +0 -0
  373. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_table_audit.py +0 -0
  374. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_table_cell.py +0 -0
  375. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  376. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_silent_stub_table_layout.py +0 -0
  377. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_smoke_integration.py +0 -0
  378. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_style_acceptance.py +0 -0
  379. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_style_font.py +0 -0
  380. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_style_setters_contract.py +0 -0
  381. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_table_set_cell_perf.py +0 -0
  382. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_table_style_id_resolution.py +0 -0
  383. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_temporarily_unavailable.py +0 -0
  384. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  385. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_xml_attr_guard.py +0 -0
  386. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/tests/test_zod_wire_contract.py +0 -0
  387. {athena_python_docx-0.24.0 → athena_python_docx-0.25.0}/uv.lock +0 -0
@@ -268,7 +268,14 @@ Issue numbers reference `python-openxml/python-docx`.
268
268
  inside_horizontal=, inside_vertical=)`** + **`_Cell.borders`**
269
269
  property + **`Table.set_borders(...)`** — per-edge border control.
270
270
  python-docx issue #201 (5 👍), #1238 demand a cell-borders API.
271
- Routes through `SetCellBorders` / `SetTableBorders`.
271
+ Routes through `SetCellBorders` / `SetTableBorders`. Each edge is
272
+ `{"style", "size_pt", "color", "space"}` (points; `sizePt` also
273
+ accepted) or `"single 0.5pt #D9D9D9"`; the SDK validates it and sends
274
+ `{style, sizePt, color: "#RRGGBB", space}`. Any other key (`val`, `sz`,
275
+ `size`, `width`) raises `ValueError` naming the accepted form, and
276
+ docx-studio refuses it too (`InvalidBorderSpec`): such edges were once
277
+ stored without their size and colour, and one with no style broke every
278
+ later export of the document.
272
279
 
273
280
  - **`_Cell.set_shading(*, fill=, pattern=, color=)`** +
274
281
  **`_Cell.shading`** property — cell fill / shading. python-docx
@@ -370,7 +377,29 @@ Issue numbers reference `python-openxml/python-docx`.
370
377
  include_revisions=False) -> bytes`** — render to PDF. python-docx
371
378
  issue #113 was closed as
372
379
  wontfix upstream but the request keeps recurring. Routes through
373
- `ExportPDF` (DOCX Studio handles the actual conversion).
380
+ `ExportPDF` (0.25.0+ opens the session first and sends buffered edits in
381
+ the same request). DOCX Studio lays the document out with the engine the
382
+ editor paginates with and paints every page onto Skia's PDF backend: a
383
+ vector PDF with selectable text in embedded fonts that matches
384
+ `render_page` — no LibreOffice anywhere, so never install it in a sandbox.
385
+ `quality` is `"draft"` (pictures as JPEG), `"standard"` (default) or
386
+ `"high"`; `include_revisions=True` shows tracked changes as markup (the
387
+ default renders them accepted); `destination` writes a local file and
388
+ refuses asset ids and URLs with `ValueError`. A deployment that cannot
389
+ produce the PDF raises `DocxUnsupportedCommandError` naming the reason.
390
+ `GET /docs/:id/export.pdf` serves the same PDF read-only (VIEW gate).
391
+
392
+ - **`Document.render_page(page_number=1, scale=2, as_pil=False)`** +
393
+ **`Document.screenshot_to_path(path, page=1, scale=2) -> Path`** +
394
+ **`Document.page_count`** (0.25.0+) — look at the document as the editor
395
+ lays it out: one page (numbered from 1) as PNG bytes or a Pillow image,
396
+ written to disk, and the page count. Names follow
397
+ athena-python-pptx's `slide.render(scale=2, as_pil=True)` and
398
+ athena-openpyxl's `Worksheet.screenshot_to_path`. Buffered edits flush
399
+ first. Backed by docx-studio's read-only `GET /docs/:id/pages/:n.png` and
400
+ `GET /docs/:id/layout.json` (VIEW gate, the SDK's API key); a page past
401
+ the end raises `PageOutOfRangeError` (an `IndexError`) carrying
402
+ `page_count`.
374
403
 
375
404
  - **`Document.clear()`** (0.14.0+) — empty the document body so subsequent
376
405
  writes start from a clean slate. python-docx has no equivalent (it
@@ -754,12 +783,19 @@ architecture or a DOCX Studio constraint:
754
783
  cheaply enumerate every cell. `(0,0)` and in-range negative indices
755
784
  behave identically to upstream.
756
785
 
757
- - **`BaseStyle.style_id` returns the display name for built-ins** (so
758
- `style_id == name`). The SDK is HTTP-only and can't read `styles.xml`
759
- to recover the OOXML styleId (`"Heading 1"` → `"Heading1"`); the wire
760
- format also uses the display name as the style id. Consequently
761
- `get_by_id("Heading1", …)` / `"Heading1" in styles` won't resolve the
762
- OOXML-id form (use the display name).
786
+ - **Unknown paragraph style names raise only when Word has no such
787
+ built-in.** Style names and ids follow python-docx: `.name` is the UI
788
+ name (`"Heading 1"`), `.style_id` the id (`"Heading1"`), read from the
789
+ document's style table (docx-studio `Info` with `includeStyles`, fetched
790
+ once per session in `docx/styles/_table.py`). A style set by name or id
791
+ is sent as the document's id, and an unstyled paragraph reads as the
792
+ default paragraph style. `paragraph.style = …` raises `KeyError` for a
793
+ name the document defines no style for, like python-docx — except Word's
794
+ built-in styles (`"Heading 4"`, `"List Bullet"`, `"Title"`…), which many
795
+ templates never write into `styles.xml` until used. Those are sent by
796
+ their Word id; Word and docx-studio apply the built-in definition. Against
797
+ an older docx-studio (no style table) a built-in name is sent as its id
798
+ and anything else as given.
763
799
 
764
800
  - **`Document.add_table(rows, cols)` requires `rows >= 1` and
765
801
  `cols >= 1`.** Upstream allows a 0-row/0-col grid you later populate,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.24.0
3
+ Version: 0.25.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.24.0"
9
+ __version__ = "0.25.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -341,6 +341,10 @@ class CommandBuffer:
341
341
  self._asset_id: str = asset_id
342
342
  self._pending: list[Command] = []
343
343
  self._lock: threading.RLock = threading.RLock()
344
+ # Held for the whole of a flush (drain + POST), so batches reach the
345
+ # server one at a time and in order, and a flush returns only once
346
+ # every batch taken before it has been delivered.
347
+ self._post_lock: threading.RLock = threading.RLock()
344
348
  self._timer: threading.Timer | None = None
345
349
  self._auto_flush_seconds: float = auto_flush_seconds
346
350
  self._closed: bool = False
@@ -532,6 +536,14 @@ class CommandBuffer:
532
536
  proxies pick up real ids without the caller ever seeing the
533
537
  UUID swap.
534
538
  """
539
+ # One batch in flight at a time: a flush that finds the queue empty
540
+ # still waits for a batch the idle timer already took and is posting,
541
+ # so a read that follows (a query, a page render) sees those edits and
542
+ # a failure of that batch is raised here.
543
+ with self._post_lock:
544
+ return self._flush_in_order()
545
+
546
+ def _flush_in_order(self) -> list[Any]:
535
547
  self._assert_current_execution()
536
548
  self._raise_deferred_flush_error()
537
549
  with self._lock:
@@ -599,7 +611,12 @@ class CommandBuffer:
599
611
  still get their real ids written back via the same flush-time
600
612
  rewrite that :meth:`flush` does.
601
613
  """
614
+ with self._post_lock:
615
+ return self._eager_flush_in_order(cmd)
616
+
617
+ def _eager_flush_in_order(self, cmd: Command) -> Any:
602
618
  self._assert_current_execution()
619
+ self._raise_deferred_flush_error()
603
620
  with self._lock:
604
621
  self._cancel_timer_locked()
605
622
  pending = self._pending
@@ -31,15 +31,16 @@ from __future__ import annotations
31
31
 
32
32
  import json
33
33
  import os
34
+ import urllib.parse
34
35
  import warnings
35
- from typing import Any
36
+ from typing import Any, TypedDict
36
37
 
37
38
  import requests
38
39
  from requests.adapters import HTTPAdapter
39
40
  from urllib3.util.retry import Retry
40
41
 
41
42
  from docx._buffer import CommandBuffer
42
- from docx._timeouts import timeout_for_commands
43
+ from docx._timeouts import DEFAULT_OP_TIMEOUT_SECONDS, timeout_for_commands
43
44
  from docx.commands import (
44
45
  BlocksList,
45
46
  BookmarksGet,
@@ -177,6 +178,7 @@ from docx.errors import (
177
178
  DocxUnsupportedCommandWarning,
178
179
  NotFoundError,
179
180
  SessionError,
181
+ _missing_block_id,
180
182
  )
181
183
 
182
184
 
@@ -338,6 +340,19 @@ _TABLE_CLIENT_ID_HINT: str = (
338
340
  )
339
341
 
340
342
 
343
+ _HEADER_FOOTER_PARAGRAPH_HINT: str = (
344
+ "\n\nHint: this paragraph is in a header or footer (``section.header`` / "
345
+ "``section.footer``), not in a table cell. docx-studio found no "
346
+ "paragraph with this id: the header/footer part that held it was "
347
+ "deleted, or the docx-studio server predates run and paragraph edits "
348
+ "in headers and footers. Add the paragraph again with "
349
+ "``section.footer.add_paragraph(text)`` (or ``section.header``) and edit "
350
+ "the paragraph it returns; until the server supports those edits, pass "
351
+ "the paragraph's full text to ``add_paragraph`` and set only its style "
352
+ "and alignment."
353
+ )
354
+
355
+
341
356
  def _looks_like_not_found(parsed: dict) -> bool:
342
357
  """Inspect a docx-studio partial-failure dict and decide whether it
343
358
  describes a "no such entity" miss (vs. a real transport / validation
@@ -446,7 +461,9 @@ def _build_retry_session() -> requests.Session:
446
461
  "other": 0,
447
462
  "backoff_factor": 2.0,
448
463
  "status_forcelist": (429, 502, 503, 504),
449
- "allowed_methods": frozenset(["POST"]),
464
+ # GET serves only the read-only render routes (page PNGs, layout),
465
+ # which are always safe to retry.
466
+ "allowed_methods": frozenset(["POST", "GET"]),
450
467
  "raise_on_status": False,
451
468
  "respect_retry_after_header": True,
452
469
  }
@@ -482,6 +499,16 @@ def _parse_retry_after(value: str | None) -> float | None:
482
499
  return None
483
500
 
484
501
 
502
+ def _delegation_headers() -> dict[str, str]:
503
+ """The user a service-key caller acts for, as ``X-Custom-Attributions``.
504
+
505
+ docx-studio's ownership gate reads it (``delegatedUserId``) and agora's
506
+ ``/access`` refuses a service-key call that delegates no one, so every
507
+ request carries it: commands and the read-only GETs alike."""
508
+ custom_attr = os.environ.get("ATHENA_DOCX_CUSTOM_ATTRIBUTIONS")
509
+ return {"X-Custom-Attributions": custom_attr} if custom_attr else {}
510
+
511
+
485
512
  def _http_post_json(
486
513
  *,
487
514
  session: requests.Session,
@@ -489,17 +516,21 @@ def _http_post_json(
489
516
  api_key: str,
490
517
  body: dict,
491
518
  timeout: float = 60.0,
519
+ header_footer_block_ids: "set[str] | frozenset[str]" = frozenset(),
492
520
  ) -> dict:
493
- """POST JSON, parse JSON, raise typed errors on non-2xx."""
521
+ """POST JSON, parse JSON, raise typed errors on non-2xx.
522
+
523
+ ``header_footer_block_ids`` are the header/footer paragraph ids this
524
+ document's ``_HeaderFooter.add_paragraph`` returned: a ``block not
525
+ found`` on one of them gets the header/footer hint.
526
+ """
494
527
  headers = {
495
528
  "Content-Type": "application/json",
496
529
  "Authorization": f"Bearer {api_key}",
497
530
  "Accept": "application/json",
498
531
  "User-Agent": _user_agent(),
532
+ **_delegation_headers(),
499
533
  }
500
- custom_attr = os.environ.get("ATHENA_DOCX_CUSTOM_ATTRIBUTIONS")
501
- if custom_attr:
502
- headers["X-Custom-Attributions"] = custom_attr
503
534
  try:
504
535
  resp = session.post(
505
536
  url,
@@ -621,7 +652,9 @@ def _http_post_json(
621
652
  isinstance(cmd_type, str) and cmd_type in _PARAGRAPH_TARGETING_COMMANDS
622
653
  )
623
654
  table_query = isinstance(cmd_type, str) and cmd_type in _TABLE_QUERY_COMMANDS
624
- if paragraph_targeting:
655
+ if _missing_block_id(err_obj.get("message")) in header_footer_block_ids:
656
+ hint = _HEADER_FOOTER_PARAGRAPH_HINT
657
+ elif paragraph_targeting:
625
658
  hint = _CELL_PARAGRAPH_HINT
626
659
  elif table_query:
627
660
  hint = _TABLE_CLIENT_ID_HINT
@@ -696,6 +729,63 @@ def _warn_skipped_commands(skipped: list[Any]) -> None:
696
729
  warnings.warn(message, DocxUnsupportedCommandWarning, stacklevel=2)
697
730
 
698
731
 
732
+ def _http_get(
733
+ *,
734
+ session: requests.Session,
735
+ url: str,
736
+ api_key: str,
737
+ params: dict[str, str] | None = None,
738
+ timeout: float = DEFAULT_OP_TIMEOUT_SECONDS,
739
+ ) -> requests.Response:
740
+ """GET one of docx-studio's read-only routes; raise typed errors on non-2xx.
741
+
742
+ A 404 keeps the server's JSON body as the error payload, so a caller can
743
+ tell a page past the end (``error: "PageNotFound"``, ``pageCount``) from an
744
+ asset the caller cannot read.
745
+ """
746
+ headers = {
747
+ "Authorization": f"Bearer {api_key}",
748
+ "User-Agent": _user_agent(),
749
+ **_delegation_headers(),
750
+ }
751
+ try:
752
+ resp = session.get(url, params=params, headers=headers, timeout=timeout)
753
+ except requests.Timeout as e:
754
+ raise SessionError(f"docx-studio timed out at {url}: {e}") from e
755
+ except requests.ConnectionError as e:
756
+ raise SessionError(f"Unable to reach docx-studio at {url}: {e}") from e
757
+ if 200 <= resp.status_code < 300:
758
+ return resp
759
+ err_body: str = resp.text
760
+ if resp.status_code in (401, 403):
761
+ raise AuthenticationError(
762
+ f"docx-studio rejected the request (HTTP {resp.status_code}): {err_body}",
763
+ )
764
+ if resp.status_code == 404:
765
+ try:
766
+ parsed: object = resp.json()
767
+ except ValueError:
768
+ parsed = None
769
+ payload: dict[str, Any] = {"status": 404, "body": err_body}
770
+ if isinstance(parsed, dict):
771
+ payload.update(parsed)
772
+ raise NotFoundError(f"docx-studio returned HTTP 404: {err_body}", payload=payload)
773
+ if resp.status_code in (502, 503, 504):
774
+ raise DocxStudioTemporarilyUnavailable(
775
+ f"docx-studio returned HTTP {resp.status_code}: {err_body}",
776
+ http_status=resp.status_code,
777
+ retry_after_seconds=_parse_retry_after(resp.headers.get("Retry-After")),
778
+ )
779
+ raise DocxError(f"docx-studio returned HTTP {resp.status_code}: {err_body}")
780
+
781
+
782
+ class RenderedPagePng(TypedDict):
783
+ """One page from ``GET /docs/:id/pages/:n.png``."""
784
+
785
+ png: bytes
786
+ page_count: int
787
+
788
+
699
789
  # ---------------------------------------------------------------------------
700
790
  # HttpClient — the bare HTTP transport. Stateless wrt batching.
701
791
  # ---------------------------------------------------------------------------
@@ -720,6 +810,8 @@ class HttpClient:
720
810
  self._base_url: str = base_url.rstrip("/")
721
811
  self._api_key: str = api_key
722
812
  self._session: requests.Session = session or _build_retry_session()
813
+ # Header/footer paragraph ids, for the ``block not found`` hint.
814
+ self.header_footer_block_ids: set[str] = set()
723
815
 
724
816
  def close(self) -> None:
725
817
  """Release the pooled HTTP connections held by ``requests.Session``.
@@ -801,6 +893,7 @@ class HttpClient:
801
893
  api_key=self._api_key,
802
894
  body=body,
803
895
  timeout=timeout_for_commands(commands=commands),
896
+ header_footer_block_ids=self.header_footer_block_ids,
804
897
  )
805
898
  applied = resp.get("applied")
806
899
  # Commands the engine doesn't implement yet are reported in
@@ -852,6 +945,38 @@ class HttpClient:
852
945
  skipped_by_index[idx] = entry
853
946
  return results, skipped_by_index
854
947
 
948
+ def _doc_url(self, asset_id: str, path: str) -> str:
949
+ return f"{self._base_url}/docs/{urllib.parse.quote(asset_id, safe='')}/{path}"
950
+
951
+ def get_layout(self, asset_id: str) -> dict[str, Any]:
952
+ """``GET /docs/:id/layout.json`` — the page count and page sizes as
953
+ DOCX Studio's layout engine paginates the document (VIEW gate)."""
954
+ resp = _http_get(
955
+ session=self._session,
956
+ url=self._doc_url(asset_id, "layout.json"),
957
+ api_key=self._api_key,
958
+ )
959
+ try:
960
+ data: object = resp.json()
961
+ except ValueError as e:
962
+ raise DocxError(f"docx-studio returned a non-JSON layout: {resp.text[:200]!r}") from e
963
+ if not isinstance(data, dict):
964
+ raise DocxError(f"docx-studio returned an unexpected layout: {data!r}")
965
+ return data
966
+
967
+ def render_page_png(self, asset_id: str, page_number: int, *, scale: float) -> RenderedPagePng:
968
+ """``GET /docs/:id/pages/:n.png?scale=`` — one page (1-indexed) as PNG,
969
+ from the same layout engine the editor paginates with (VIEW gate)."""
970
+ resp = _http_get(
971
+ session=self._session,
972
+ url=self._doc_url(asset_id, f"pages/{page_number}.png"),
973
+ api_key=self._api_key,
974
+ params={"scale": f"{scale:g}"},
975
+ )
976
+ page_count_header = resp.headers.get("X-Page-Count", "")
977
+ page_count = int(page_count_header) if page_count_header.isdigit() else 0
978
+ return RenderedPagePng(png=resp.content, page_count=page_count)
979
+
855
980
 
856
981
  # ---------------------------------------------------------------------------
857
982
  # Path proxy — translates dotted paths + camelCase param dicts into typed
@@ -1045,6 +1170,7 @@ _FIELD_RENAMES: dict[str, dict[str, str]] = {
1045
1170
  # path-proxy snake-case transform leaves `in` as a Python keyword
1046
1171
  # collision; rename to `in_` here so the dataclass accepts it.
1047
1172
  "find_replace": {"in": "in_"},
1173
+ "blocks.list": {"in": "in_"},
1048
1174
  "find_text": {"in": "in_"},
1049
1175
  "iter_runs": {"in": "in_"},
1050
1176
  "numbering.list": {"in": "in_"},
@@ -2055,7 +2055,7 @@ def _border_spec_to_ooxml_attrs(spec: dict[str, Any]) -> dict[str, str]:
2055
2055
  out["sz"] = str(int(round(float(size_pt) * 8)))
2056
2056
  except (TypeError, ValueError):
2057
2057
  pass
2058
- space = spec.get("space_pt")
2058
+ space = spec.get("space", spec.get("space_pt"))
2059
2059
  if space is not None:
2060
2060
  try:
2061
2061
  out["space"] = str(int(round(float(space))))
@@ -22,6 +22,8 @@ _LONG_RUNNING_COMMAND_TYPES: frozenset[str] = frozenset(
22
22
  # ``Document.clear()`` replaces the whole body story in one write;
23
23
  # on a large document that single command can outlast the 60s budget.
24
24
  "ClearBody",
25
+ # ``Document.to_pdf()`` lays out and paints every page of the document.
26
+ "ExportPDF",
25
27
  }
26
28
  )
27
29
 
@@ -178,6 +178,22 @@ class Session:
178
178
  )
179
179
  return self._doc_handle
180
180
 
181
+ @property
182
+ def http_client(self) -> Any:
183
+ """The opened :class:`HttpClient`, for docx-studio's read-only routes
184
+ outside the command bus (page renders, layout)."""
185
+ self._assert_current_execution()
186
+ if not self._opened:
187
+ raise SessionError(
188
+ "Session not yet opened; call await session.open() first "
189
+ "or use the sync facade via Document().",
190
+ )
191
+ if self._closed:
192
+ raise DocumentClosedError(
193
+ f"Session for asset {self._asset_id} is closed.",
194
+ )
195
+ return self._client
196
+
181
197
  async def send_command(self, cmd: Any) -> Any:
182
198
  """Route a pre-built :class:`docx.commands.Command` through the
183
199
  buffer.
@@ -88,6 +88,8 @@ class CreateParagraph(Command):
88
88
  # serialises as ``in`` on the wire (see top-of-module helper).
89
89
  in_: dict[str, Any] | None = None
90
90
  client_node_id: str | None = None
91
+ # The paragraph opens with a page break (``Document.add_page_break``).
92
+ page_break: bool | None = None
91
93
 
92
94
 
93
95
  @dataclass
@@ -543,6 +545,9 @@ class BlocksList(Command):
543
545
  # ``Paragraph.text``/``.runs``/``.style`` from one list instead of a
544
546
  # ``get_node_by_id`` per paragraph. Serialized to ``includeRuns`` on the wire.
545
547
  include_runs: bool | None = None
548
+ # A header/footer story (``headerFooterSlot``) for ``header.paragraphs``;
549
+ # ``in`` on the wire. See CreateParagraph.in_.
550
+ in_: dict[str, Any] | None = None
546
551
 
547
552
 
548
553
  @dataclass
@@ -573,7 +578,10 @@ class ImagesList(Command):
573
578
 
574
579
  @dataclass
575
580
  class Info(Command):
576
- pass
581
+ # ``True`` also returns the document's style table (``styleTable``: the
582
+ # id, styles.xml name, type and default flag of every style); an older
583
+ # docx-studio ignores the field and sends no table.
584
+ include_styles: bool | None = None
577
585
 
578
586
 
579
587
  @dataclass
@@ -1004,6 +1012,11 @@ class CreateField(Command):
1004
1012
  target: dict[str, Any] | None = None
1005
1013
  cached_result: str | None = None
1006
1014
  client_entity_id: str | None = None
1015
+ # False for an empty run: the field takes the paragraph style's defaults,
1016
+ # not the formatting of the text before it.
1017
+ inherit_marks: bool | None = None
1018
+ # The formatting set on that empty run before it has text (``FormatApply.inline``).
1019
+ inline: dict[str, Any] | None = None
1007
1020
 
1008
1021
 
1009
1022
  @dataclass
@@ -1616,10 +1629,12 @@ class IterRuns(Command):
1616
1629
 
1617
1630
  @dataclass
1618
1631
  class ExportPDF(Command):
1619
- """Render the document to a PDF byte stream, optionally storing it
1620
- under ``destination`` (an asset id, S3 URL, or path).
1632
+ """Render the document to a PDF with DOCX Studio's layout engine.
1621
1633
 
1622
- Returns ``{bytes_base64, asset_id?, page_count}``.
1634
+ Returns ``{bytesBase64, mediaType, pageCount, fidelityNotes}``. The
1635
+ server refuses ``destination`` (``Document.to_pdf`` writes local files
1636
+ itself and never sends it); ``quality`` is ``"draft"`` | ``"standard"`` |
1637
+ ``"high"``.
1623
1638
  """
1624
1639
 
1625
1640
  quality: str | None = None # "draft" | "standard" | "high"
@@ -1772,6 +1787,9 @@ _RESPONSE_BEARING_TYPES: frozenset[str] = frozenset(
1772
1787
  "HeaderFootersPartsCreate",
1773
1788
  # HeaderFootersPartsList is a read-side query.
1774
1789
  "HeaderFootersPartsList",
1790
+ # HeaderFootersPartsDelete returns {changed}: whether a part was
1791
+ # deleted. Buffered, the caller only ever saw ``{}``.
1792
+ "HeaderFootersPartsDelete",
1775
1793
  # Athena-extension response-bearing creates — each returns an
1776
1794
  # entity id the caller wraps in a proxy.
1777
1795
  "CreateHyperlink",