athena-python-docx 0.34.0__tar.gz → 0.35.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 (486) hide show
  1. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/AGENTS.md +21 -19
  2. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_buffer.py +6 -0
  5. athena_python_docx-0.35.0/docx/_proxy.py +85 -0
  6. athena_python_docx-0.35.0/docx/_xml_text.py +46 -0
  7. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/blkcntnr.py +3 -0
  8. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/document.py +4 -0
  9. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/section.py +3 -0
  10. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/settings.py +15 -1
  11. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/styles/style.py +65 -18
  12. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/styles/styles.py +5 -1
  13. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/table.py +89 -14
  14. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/paragraph.py +33 -3
  15. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/parfmt.py +16 -4
  16. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/run.py +21 -2
  17. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/pyproject.toml +1 -1
  18. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/METHODOLOGY.md +9 -1
  19. athena_python_docx-0.35.0/tests/fidelity/ab_probe/__init__.py +15 -0
  20. athena_python_docx-0.35.0/tests/fidelity/ab_probe/default_style_run_formatting.py +25 -0
  21. athena_python_docx-0.35.0/tests/fidelity/ab_probe/header_footer_pictures.py +28 -0
  22. athena_python_docx-0.35.0/tests/fidelity/ab_probe/less_used_writes.py +219 -0
  23. athena_python_docx-0.35.0/tests/fidelity/ab_probe/merged_cell_identity.py +31 -0
  24. athena_python_docx-0.35.0/tests/fidelity/ab_probe/paragraph_text_setter.py +57 -0
  25. athena_python_docx-0.35.0/tests/fidelity/ab_probe/proxy_equality.py +41 -0
  26. athena_python_docx-0.35.0/tests/fidelity/ab_probe/xml_incompatible_text.py +24 -0
  27. athena_python_docx-0.35.0/tests/fidelity/ab_probe/zero_and_negative_indents.py +26 -0
  28. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/ab_probe_cases.py +196 -0
  29. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -1
  30. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/baseline.json +8 -0
  31. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/fixture_scripts.py +17 -0
  32. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/runner.py +25 -16
  33. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/test_live_runner.py +24 -0
  34. athena_python_docx-0.35.0/tests/test_battery_cases.py +54 -0
  35. athena_python_docx-0.35.0/tests/test_document_settings_session_open.py +63 -0
  36. athena_python_docx-0.35.0/tests/test_merged_cell_identity.py +104 -0
  37. athena_python_docx-0.35.0/tests/test_paragraph_indent_reads.py +60 -0
  38. athena_python_docx-0.35.0/tests/test_paragraph_text_empty_run.py +44 -0
  39. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_parfmt_clears.py +24 -0
  40. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_parity_misc.py +15 -2
  41. athena_python_docx-0.35.0/tests/test_proxy_equality.py +179 -0
  42. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_tab_stops.py +42 -0
  43. athena_python_docx-0.35.0/tests/test_unmapped_alignment_reads.py +95 -0
  44. athena_python_docx-0.35.0/tests/test_xml_incompatible_text.py +103 -0
  45. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/uv.lock +1 -1
  46. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/.gitignore +0 -0
  47. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/CLAUDE.md +0 -0
  48. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/DOCX_EXEC_LAB.md +0 -0
  49. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/README.md +0 -0
  50. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_athena_extension.py +0 -0
  51. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_batching.py +0 -0
  52. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_capabilities.py +0 -0
  53. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_citations.py +0 -0
  54. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_execution.py +0 -0
  55. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_http.py +0 -0
  56. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_http_doc.py +0 -0
  57. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_image_utils.py +0 -0
  58. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_postproc.py +0 -0
  59. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_ptc.py +0 -0
  60. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_references.py +0 -0
  61. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_run_order.py +0 -0
  62. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_table_styles.py +0 -0
  63. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_timeouts.py +0 -0
  64. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/_tracked.py +0 -0
  65. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/api.py +0 -0
  66. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/bookmarks.py +0 -0
  67. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/charts.py +0 -0
  68. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/client.py +0 -0
  69. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/commands.py +0 -0
  70. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/comments.py +0 -0
  71. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/drawing/__init__.py +0 -0
  72. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/__init__.py +0 -0
  73. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/base.py +0 -0
  74. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/dml.py +0 -0
  75. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/section.py +0 -0
  76. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/shape.py +0 -0
  77. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/style.py +0 -0
  78. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/table.py +0 -0
  79. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/enum/text.py +0 -0
  80. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/errors.py +0 -0
  81. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/exceptions.py +0 -0
  82. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/fields.py +0 -0
  83. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/footnotes.py +0 -0
  84. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/image/__init__.py +0 -0
  85. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/image/exceptions.py +0 -0
  86. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/image/image.py +0 -0
  87. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/math.py +0 -0
  88. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/opc/__init__.py +0 -0
  89. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/opc/coreprops.py +0 -0
  90. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/oxml/__init__.py +0 -0
  91. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/revisions.py +0 -0
  92. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/sdt.py +0 -0
  93. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/session.py +0 -0
  94. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/shape.py +0 -0
  95. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/shared.py +0 -0
  96. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/styles/__init__.py +0 -0
  97. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/styles/_table.py +0 -0
  98. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/styles/latent.py +0 -0
  99. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/__init__.py +0 -0
  100. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/font.py +0 -0
  101. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/hyperlink.py +0 -0
  102. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/pagebreak.py +0 -0
  103. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/text/tabstops.py +0 -0
  104. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/toc.py +0 -0
  105. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/docx/typing.py +0 -0
  106. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/docx_exec_lab.py +0 -0
  107. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  108. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  109. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/docx_exec_lab_server.py +0 -0
  110. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/dump_wire_fixtures.py +0 -0
  111. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/release.sh +0 -0
  112. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/round_trip_smoke.py +0 -0
  113. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/smoke_test_block_not_found.py +0 -0
  114. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/scripts/validate_find_replace_asset.py +0 -0
  115. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/__init__.py +0 -0
  116. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/conftest.py +0 -0
  117. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/README.md +0 -0
  118. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/__init__.py +0 -0
  119. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/ab_probe_runner.py +0 -0
  120. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/auto_gen_cases.py +0 -0
  121. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/binary_round_trip.py +0 -0
  122. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/cases.py +0 -0
  123. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/complex_cases.py +0 -0
  124. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/coverage_report.py +0 -0
  125. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/extract.py +0 -0
  126. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/extreme_cases.py +0 -0
  127. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/fake_session.py +0 -0
  128. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/README.md +0 -0
  129. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  130. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  131. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  132. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  133. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  134. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/local_runner.py +0 -0
  135. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/mega_cases.py +0 -0
  136. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshot.py +0 -0
  137. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  138. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  139. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  140. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  141. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  142. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  143. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  144. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  145. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  146. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  147. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  148. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  149. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  150. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  151. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  152. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  153. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  154. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  155. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  156. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  157. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  158. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  159. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  160. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  161. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  162. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  163. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  164. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  165. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  166. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  167. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  168. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  169. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  170. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  171. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  172. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  173. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  174. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  175. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  176. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  177. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  178. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  179. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  180. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  181. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  182. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  183. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  184. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  185. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  186. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  187. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  188. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  189. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  190. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  191. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  192. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  193. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  194. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  195. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  196. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  197. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  198. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  199. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  200. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  201. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  202. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  203. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  204. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  205. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  206. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  207. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  208. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  209. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  210. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  211. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  212. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  213. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  214. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  215. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  216. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  217. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  218. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  219. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  220. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  221. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  222. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  223. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  224. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  225. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  226. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  227. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  228. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  229. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  230. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  231. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  232. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  233. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  234. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  235. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  236. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  237. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  238. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  239. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  240. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  241. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  242. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  243. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  244. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  245. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  246. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  247. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  248. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  249. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  250. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  251. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  252. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  253. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  254. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  255. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  256. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  257. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  258. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  259. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  260. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  261. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  262. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  263. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  264. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  265. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  266. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  267. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  268. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  269. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  270. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  271. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  272. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  273. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  274. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  275. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  276. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  277. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  278. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  279. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  280. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  281. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  282. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  283. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  284. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  285. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  286. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  287. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  288. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/ours_spec.json +0 -0
  289. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/parity_crawl.py +0 -0
  290. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/parity_diff.json +0 -0
  291. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/real_world_cases.py +0 -0
  292. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/round_trip_tests.py +0 -0
  293. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/stock_spec.json +0 -0
  294. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  295. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fixtures/field_reads.json +0 -0
  296. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fixtures/note_reference_reads.json +0 -0
  297. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fixtures/ruby_reads.json +0 -0
  298. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/fixtures/symbol_reads.json +0 -0
  299. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/__init__.py +0 -0
  300. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/reader.py +0 -0
  301. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/sdk_driver.py +0 -0
  302. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/live/stock_driver.py +0 -0
  303. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/README.md +0 -0
  304. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/__init__.py +0 -0
  305. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/baseline_gaps.json +0 -0
  306. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/compare.py +0 -0
  307. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/intentional_deviations.json +0 -0
  308. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/introspect.py +0 -0
  309. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  310. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/reports/gap_report.json +0 -0
  311. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/run_parity.py +0 -0
  312. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/snapshots/athena_latest.json +0 -0
  313. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  314. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/parity/test_parity_gap.py +0 -0
  315. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_add_section.py +0 -0
  316. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_add_section_extract_items.py +0 -0
  317. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_alignment_values.py +0 -0
  318. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  319. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_athena_extensions_contract.py +0 -0
  320. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_athena_extensions_registry.py +0 -0
  321. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_batch_chunking.py +0 -0
  322. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_batching_perf.py +0 -0
  323. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_block_not_found_error.py +0 -0
  324. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_buffer.py +0 -0
  325. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  326. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_add_table_not_supported.py +0 -0
  327. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_borders_spec.py +0 -0
  328. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_fastpath_runs.py +0 -0
  329. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  330. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  331. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_inner_format_stash.py +0 -0
  332. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  333. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_inner_run_guard.py +0 -0
  334. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_merge.py +0 -0
  335. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_nested_tables.py +0 -0
  336. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_paragraphs_listed.py +0 -0
  337. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  338. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_cell_text_replace_semantics.py +0 -0
  339. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_citations.py +0 -0
  340. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_collapsed_range_format.py +0 -0
  341. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_color_format_theme.py +0 -0
  342. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_command_dataclasses.py +0 -0
  343. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_commands.py +0 -0
  344. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_comment_paragraphs.py +0 -0
  345. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_comments.py +0 -0
  346. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_comments_first_read.py +0 -0
  347. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_content_control_value.py +0 -0
  348. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_core_properties.py +0 -0
  349. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_document_asset_id_property.py +0 -0
  350. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_document_clear.py +0 -0
  351. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_document_create.py +0 -0
  352. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_document_create_from_template.py +0 -0
  353. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_document_factory_validation.py +0 -0
  354. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_docx_exec_lab.py +0 -0
  355. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_docx_exec_lab_server.py +0 -0
  356. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_drawing_image.py +0 -0
  357. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  358. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_empty_hyperlinks.py +0 -0
  359. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_enum_parity.py +0 -0
  360. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_execution_scope.py +0 -0
  361. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_export_docx_clean.py +0 -0
  362. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_export_rescue_anchors.py +0 -0
  363. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  364. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_field_refresh.py +0 -0
  365. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_field_runs.py +0 -0
  366. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_find_replace_session_open.py +0 -0
  367. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_flushed_write_failures.py +0 -0
  368. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_http_transport.py +0 -0
  369. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_hyperlink_coalescing.py +0 -0
  370. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_image_url_data_uri.py +0 -0
  371. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_inline_page_break.py +0 -0
  372. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_inline_shape_alt_text.py +0 -0
  373. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_inline_shape_size.py +0 -0
  374. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_inline_shape_type.py +0 -0
  375. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_inline_shapes_floating.py +0 -0
  376. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_insert_deferred.py +0 -0
  377. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_iter_inner_content.py +0 -0
  378. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_latent_style_writes.py +0 -0
  379. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_line_clear_break.py +0 -0
  380. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_list_styles.py +0 -0
  381. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  382. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_merged_cells.py +0 -0
  383. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_missing_modules.py +0 -0
  384. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_nested_table_refused.py +0 -0
  385. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  386. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_oxml_shim.py +0 -0
  387. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_page_break.py +0 -0
  388. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_paragraph_delete.py +0 -0
  389. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  390. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_paragraph_text_len_cache.py +0 -0
  391. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_parity_round2.py +0 -0
  392. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_partial_failure_cascade.py +0 -0
  393. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  394. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_phase_a_behavior.py +0 -0
  395. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_phase_b_headers_footers.py +0 -0
  396. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_phase_c_tables.py +0 -0
  397. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_positional_cell_id.py +0 -0
  398. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  399. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  400. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_postproc_ref_restore.py +0 -0
  401. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_pr19766_review_fixes.py +0 -0
  402. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_ptc.py +0 -0
  403. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_python_docx_api_parity.py +0 -0
  404. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_read_run_ranges.py +0 -0
  405. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_rendered_page_breaks.py +0 -0
  406. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_repeated_node_read.py +0 -0
  407. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_restart_numbering.py +0 -0
  408. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_revisions.py +0 -0
  409. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_round_trip_smoke_script.py +0 -0
  410. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  411. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_add_picture_anchor.py +0 -0
  412. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_break_inner_content.py +0 -0
  413. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_edges.py +0 -0
  414. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_formatting_wire.py +0 -0
  415. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_identity.py +0 -0
  416. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_later_runs.py +0 -0
  417. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_mark_inheritance.py +0 -0
  418. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_page_number_blocks.py +0 -0
  419. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_table_style_objects.py +0 -0
  420. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_text_python_docx.py +0 -0
  421. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  422. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_run_unmodeled_toggles.py +0 -0
  423. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_sdk_reads_served.py +0 -0
  424. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_section_read_lengths.py +0 -0
  425. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  426. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_add_picture.py +0 -0
  427. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_add_run.py +0 -0
  428. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  429. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  430. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_comments_get.py +0 -0
  431. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_document_audit.py +0 -0
  432. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_document_element.py +0 -0
  433. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_enum_section.py +0 -0
  434. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_font_audit.py +0 -0
  435. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_header_footer.py +0 -0
  436. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_hyperlink.py +0 -0
  437. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_inline_shape.py +0 -0
  438. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  439. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_misc.py +0 -0
  440. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  441. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  442. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  443. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_parfmt.py +0 -0
  444. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  445. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_add_break.py +0 -0
  446. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  447. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_style.py +0 -0
  448. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  449. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_text.py +0 -0
  450. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_run_underline.py +0 -0
  451. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_section_audit.py +0 -0
  452. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  453. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_section_onoff.py +0 -0
  454. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_settings.py +0 -0
  455. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_shared_audit.py +0 -0
  456. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_style.py +0 -0
  457. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_styles.py +0 -0
  458. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_table_audit.py +0 -0
  459. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_table_cell.py +0 -0
  460. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  461. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_silent_stub_table_layout.py +0 -0
  462. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_smoke_integration.py +0 -0
  463. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_acceptance.py +0 -0
  464. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_delete.py +0 -0
  465. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_font.py +0 -0
  466. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_formatting_writes.py +0 -0
  467. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_metadata_writes.py +0 -0
  468. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_names.py +0 -0
  469. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_setters_contract.py +0 -0
  470. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_style_tab_stops_read.py +0 -0
  471. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  472. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_tab_stop_writes.py +0 -0
  473. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_anchors.py +0 -0
  474. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_clears.py +0 -0
  475. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_direction.py +0 -0
  476. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_read_reuse.py +0 -0
  477. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_set_cell_perf.py +0 -0
  478. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_table_style_id_resolution.py +0 -0
  479. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_temporarily_unavailable.py +0 -0
  480. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_text_control_characters.py +0 -0
  481. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_tracked_revisions_offsets.py +0 -0
  482. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_uv_lock_version.py +0 -0
  483. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  484. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_wire_contract.py +0 -0
  485. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_xml_attr_guard.py +0 -0
  486. {athena_python_docx-0.34.0 → athena_python_docx-0.35.0}/tests/test_zod_wire_contract.py +0 -0
@@ -1255,31 +1255,33 @@ architecture or a DOCX Studio constraint:
1255
1255
  exported file. Against a docx-studio that predates `fieldRun` reads, a
1256
1256
  field reads as no runs and no text, as before (`tests/test_field_runs.py`).
1257
1257
 
1258
- - **A run that holds a page number block refuses two whole-run formats.** A
1259
- page number block (`w:pgNum`) reads as a run with no text, and a run that
1260
- holds text and blocks (or two blocks) reads as python-docx's one run. A
1261
- whole-run format (`run.bold = True`, `run.font.*`, a format of a block's
1262
- run) formats every piece of it, as python-docx formats its `w:rPr`. Two
1263
- formats are refused while a block of the run has a node. A link's block
1264
- has none, and takes both as the run's text does. The first is a tracked
1265
- format (`track_revisions`), which raises `DocxError` naming
1266
- `TrackedChangesUnsupported`, because docx-studio records no tracked change
1267
- on a block. The second is the on/off properties no editor mark holds
1258
+ - **A run that holds a page number block refuses a tracked whole-run format
1259
+ and two text writes.** A page number block (`w:pgNum`) reads as a run with
1260
+ no text, and a run that holds text and blocks (or two blocks) reads as
1261
+ python-docx's one run. A whole-run format (`run.bold = True`, `run.font.*`,
1262
+ a format of a block's run) formats every piece of it, as python-docx formats
1263
+ its `w:rPr`, the on/off properties no editor mark holds included
1268
1264
  (`font.no_proof`, `snap_to_grid`, `web_hidden`, `spec_vanish`, `math`,
1269
- `complex_script`, `cs_bold`, `cs_italic`), in any format that reaches a
1270
- block, which warn (`DocxUnsupportedCommandWarning`), because a block keeps
1271
- its source run's.
1272
- python-docx writes both into the run's `w:rPr`. Made on the run's text
1273
- alone, either would leave the run half formatted and split it in two
1265
+ `complex_script`, `cs_bold`, `cs_italic`). A tracked format
1266
+ (`track_revisions`) is refused while a block of the run has a node, and
1267
+ raises `DocxError` naming `TrackedChangesUnsupported`, because docx-studio
1268
+ records no tracked change on a block. A link's block has none, and takes it
1269
+ as the run's text does. In a document imported before docx-studio gave a
1270
+ block's node its run's properties (in October 2026, between the release that
1271
+ first read `w:pgNum` and the next), and in a comment, the on/off properties
1272
+ are refused too, in any format that reaches a block, and warn
1273
+ (`DocxUnsupportedCommandWarning`), because there a block keeps its source
1274
+ run's. python-docx writes both into the run's `w:rPr`. Made on the run's
1275
+ text alone, either would leave the run half formatted and split it in two
1274
1276
  (`DOCX_STUDIO_LIMITATIONS.md` § 27). `run.text = …` and `clear()` replace
1275
1277
  all of such a run, its blocks too, as upstream does: the SDK declares
1276
1278
  `wholeRunPieces`, and renumbers the field runs it holds of the paragraph,
1277
1279
  since each field after the blocks is numbered one lower for each
1278
1280
  (`tests/test_run_page_number_blocks.py`). Two text writes are refused and
1279
- warn (`DocxUnsupportedCommandWarning`), where upstream replaces the
1280
- blocks: text written to a block's run (a run of blocks alone, or a lone
1281
- block), which would move the text offsets the SDK keeps, and the text of a
1282
- link's run that holds a block, which has no node to take out.
1281
+ warn (`DocxUnsupportedCommandWarning`), where upstream replaces the blocks:
1282
+ text written to a block's run (a run of blocks alone, or a lone block),
1283
+ which would move the text offsets the SDK keeps, and the text of a link's
1284
+ run that holds a block, which has no node to take out.
1283
1285
 
1284
1286
  - **`Font.name = "…"` also clears the theme fonts of the two slots it
1285
1287
  sets.** python-docx writes the name to `w:rFonts`' `w:ascii` and `w:hAnsi`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.34.0
3
+ Version: 0.35.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.34.0"
9
+ __version__ = "0.35.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -43,6 +43,7 @@ from docx._execution import (
43
43
  is_stale_execution,
44
44
  )
45
45
  from docx._timeouts import timeout_for_commands
46
+ from docx._xml_text import check_command_text
46
47
  from docx.commands import (
47
48
  Command,
48
49
  GetNodeById,
@@ -596,6 +597,11 @@ class CommandBuffer:
596
597
  proxy's ``_node_id`` in-place.
597
598
  """
598
599
  self.ensure_usable()
600
+ # A write whose text holds a character XML does not allow raises
601
+ # python-docx's ValueError here, before anything is sent: every command
602
+ # comes through, a path-proxy op's and a direct ``send_command``'s.
603
+ if not is_query(cmd):
604
+ check_command_text(cmd.to_dict())
599
605
 
600
606
  # A read of the node the last command read, with nothing sent or
601
607
  # buffered since and within READ_REUSE_SECONDS of it, answers from
@@ -0,0 +1,85 @@
1
+ """python-docx's ``ElementProxy`` equality, for the SDK's proxies of the
2
+ objects python-docx wraps in one: styles, the styles part, settings, a
3
+ paragraph's or a style's paragraph format, a run's or a style's font."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import weakref
8
+ from typing import Any
9
+
10
+
11
+ class ElementProxyEquality:
12
+ """python-docx's ``docx.shared.ElementProxy`` equality: two proxies of the
13
+ same element are equal (``paragraph.style == doc.styles["Heading 1"]``),
14
+ a proxy of another element or anything else is not, and, as python-docx
15
+ defines ``__eq__`` there, a proxy is not hashable.
16
+
17
+ The element is :meth:`_proxy_element`: the docx-studio object it stands
18
+ for, named as the XML element python-docx's proxy wraps (a style's
19
+ ``w:style``, so a style, its font and its paragraph format are equal, as
20
+ they are in python-docx).
21
+ """
22
+
23
+ __slots__ = ()
24
+
25
+ def _proxy_element(self) -> tuple[object, ...]:
26
+ raise NotImplementedError
27
+
28
+ def __eq__(self, other: object) -> bool:
29
+ if not isinstance(other, ElementProxyEquality):
30
+ return False
31
+ return self._proxy_element() == other._proxy_element()
32
+
33
+ def __ne__(self, other: object) -> bool:
34
+ return not self.__eq__(other)
35
+
36
+ __hash__ = None # type: ignore[assignment]
37
+
38
+
39
+ # Session -> style id -> the style definition that id names in the session's
40
+ # document now (:func:`style_definition`). Held weakly by session, as the
41
+ # run order is (``docx._run_order``); the document stores none of it.
42
+ _STYLE_DEFINITIONS: "weakref.WeakKeyDictionary[Any, dict[str, object]]" = weakref.WeakKeyDictionary()
43
+
44
+
45
+ def _definitions(session: object) -> "dict[str, object] | None":
46
+ if session is None:
47
+ return None
48
+ try:
49
+ return _STYLE_DEFINITIONS.setdefault(session, {})
50
+ except TypeError: # a session that takes no weak reference
51
+ return None
52
+
53
+
54
+ def style_definition(session: object, style_id: str) -> object:
55
+ """The style definition (its ``w:style`` element) that ``style_id`` names in
56
+ ``session``'s document now, which a style proxy holds from its first read:
57
+ the same one after a rename (:func:`style_renamed`), another for a style
58
+ made after one of that id was deleted (:func:`style_deleted`)."""
59
+ definitions = _definitions(session)
60
+ if definitions is None:
61
+ return ("w:styleId", style_id)
62
+ return definitions.setdefault(style_id, object())
63
+
64
+
65
+ def style_renamed(session: object, old: str, new: str) -> None:
66
+ """``style_id`` renamed the definition ``old`` named to ``new``."""
67
+ definitions = _definitions(session)
68
+ if definitions is not None:
69
+ definitions[new] = definitions.pop(old, None) or object()
70
+
71
+
72
+ def style_deleted(session: object, style_id: str) -> None:
73
+ """``delete`` removed the definition ``style_id`` named."""
74
+ definitions = _definitions(session)
75
+ if definitions is not None:
76
+ definitions.pop(style_id, None)
77
+
78
+
79
+ def style_element(style: object) -> tuple[object, ...]:
80
+ """The ``w:style`` element of ``style`` (a ``BaseStyle``): its document and
81
+ its definition (:func:`style_definition`), which a rename keeps."""
82
+ definition = getattr(style, "_definition", None)
83
+ if definition is None:
84
+ definition = ("w:styleId", getattr(style, "_style_id", None))
85
+ return ("w:style", getattr(style, "_session", None), definition)
@@ -0,0 +1,46 @@
1
+ """What lxml refuses in XML text and attribute values, where python-docx meets it.
2
+
3
+ python-docx writes every string it is given into an lxml element, and lxml
4
+ raises ``ValueError`` for a character XML does not allow: C0 controls other
5
+ than tab, LF and CR, the noncharacters U+FFFE / U+FFFF, and lone surrogates.
6
+ So ``run.text = "a\\x0bb"`` (a vertical tab, Word's line break in its object
7
+ model) raises there, before anything is written. docx-studio would take the
8
+ text, and a part holding it is one Word refuses to open.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import re
14
+ from typing import Any
15
+
16
+ XML_INCOMPATIBLE_CHARACTER = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\ud800-\udfff￾￿]")
17
+ XML_INCOMPATIBLE_MESSAGE = (
18
+ "All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters"
19
+ )
20
+
21
+
22
+ def check_xml_compatible(value: Any) -> None:
23
+ """Raise python-docx's ``ValueError`` (lxml's) when a string in ``value``,
24
+ a command's params (strings, lists, dicts), holds a character XML does
25
+ not allow."""
26
+ if isinstance(value, str):
27
+ if XML_INCOMPATIBLE_CHARACTER.search(value):
28
+ raise ValueError(XML_INCOMPATIBLE_MESSAGE)
29
+ elif isinstance(value, dict):
30
+ for item in value.values():
31
+ check_xml_compatible(item)
32
+ elif isinstance(value, (list, tuple)):
33
+ for item in value:
34
+ check_xml_compatible(item)
35
+
36
+
37
+ #: Fields of a write that name text to find, not text to write
38
+ #: (``FindReplace.pattern``): a pattern may match what a document already holds.
39
+ _SEARCH_FIELDS: frozenset[str] = frozenset({"pattern"})
40
+
41
+
42
+ def check_command_text(command: dict[str, Any]) -> None:
43
+ """:func:`check_xml_compatible` over a write's wire fields (a command's
44
+ ``to_dict()``), but for the text it searches for (``_SEARCH_FIELDS``)."""
45
+ check_xml_compatible({key: value for key, value in command.items() if key not in _SEARCH_FIELDS})
46
+
@@ -9,6 +9,8 @@ docx-studio; ``isinstance(cell, BlockItemContainer)`` holds as in python-docx.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ from docx._xml_text import check_xml_compatible
13
+
12
14
  from typing import TYPE_CHECKING, Iterator
13
15
 
14
16
  if TYPE_CHECKING:
@@ -30,6 +32,7 @@ class BlockItemContainer:
30
32
  self, text: str = "", style: "str | ParagraphStyle | None" = None
31
33
  ) -> "Paragraph":
32
34
  """Return paragraph newly added to the end of the content in this container."""
35
+ check_xml_compatible(text)
33
36
  raise NotImplementedError(f"{type(self).__name__} holds no paragraphs")
34
37
 
35
38
  def add_table(self, rows: int, cols: int, width: "Length") -> "Table":
@@ -14,6 +14,8 @@ Phase 1 supported methods:
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from docx._xml_text import check_xml_compatible
18
+
17
19
  import base64
18
20
  import os
19
21
  import re
@@ -1789,6 +1791,7 @@ class Document:
1789
1791
  Returns:
1790
1792
  The newly-created Paragraph.
1791
1793
  """
1794
+ check_xml_compatible(text)
1792
1795
  from docx.styles._table import paragraph_style_name
1793
1796
  from docx.styles.style import ParagraphStyle
1794
1797
  from docx.text.paragraph import Paragraph
@@ -2033,6 +2036,7 @@ class Document:
2033
2036
  level: int = 1,
2034
2037
  ) -> "Paragraph":
2035
2038
  """Append a heading via DOCX Studio's canonical `doc.create.heading`."""
2039
+ check_xml_compatible(text)
2036
2040
  from docx.text.paragraph import Paragraph
2037
2041
 
2038
2042
  self._ensure_open()
@@ -11,6 +11,8 @@ or twip values depending on the op).
11
11
 
12
12
  from __future__ import annotations
13
13
 
14
+ from docx._xml_text import check_xml_compatible
15
+
14
16
  import warnings
15
17
  from collections.abc import Sequence
16
18
  from typing import TYPE_CHECKING
@@ -986,6 +988,7 @@ class _HeaderFooter(BlockItemContainer):
986
988
  server turns tabs and line breaks in ``text`` into ``<w:tab/>`` /
987
989
  ``<w:br/>``, as python-docx's ``Run.text`` does.
988
990
  """
991
+ check_xml_compatible(text)
989
992
  from docx.styles.style import ParagraphStyle
990
993
 
991
994
  style_str: str | None
@@ -21,6 +21,7 @@ from __future__ import annotations
21
21
  from typing import TYPE_CHECKING
22
22
 
23
23
  from docx._batching import run_sync
24
+ from docx._proxy import ElementProxyEquality
24
25
 
25
26
  if TYPE_CHECKING:
26
27
  from docx.client import Session
@@ -38,7 +39,7 @@ class PendingSettingsMutationWarning(UserWarning):
38
39
  """
39
40
 
40
41
 
41
- class Settings:
42
+ class Settings(ElementProxyEquality):
42
43
  def __init__(
43
44
  self,
44
45
  *,
@@ -49,12 +50,16 @@ class Settings:
49
50
  self._document: "Document | None" = document
50
51
  self._odd_and_even_pages_header_footer: bool = False
51
52
 
53
+ def _proxy_element(self) -> tuple[object, ...]:
54
+ return ("w:settings", self._session)
55
+
52
56
  @property
53
57
  def odd_and_even_pages_header_footer(self) -> bool:
54
58
  """The document's ``w:evenAndOddHeaders`` in ``word/settings.xml``, as
55
59
  python-docx reads it (False when absent or off). A docx-studio that
56
60
  does not report it (``Info`` without ``settings``) gives the value this
57
61
  proxy last set."""
62
+ self._open()
58
63
  info: object = run_sync(self._session.doc.info({"includeSettings": True}))
59
64
  settings: object = info.get("settings") if isinstance(info, dict) else None
60
65
  reported: object = settings.get("evenAndOddHeaders") if isinstance(settings, dict) else None
@@ -65,6 +70,7 @@ class Settings:
65
70
  @odd_and_even_pages_header_footer.setter
66
71
  def odd_and_even_pages_header_footer(self, value: bool) -> None:
67
72
  enabled = bool(value)
73
+ self._open()
68
74
  run_sync(
69
75
  self._session.doc.sections.set_odd_even_headers_footers(
70
76
  {"enabled": enabled},
@@ -72,6 +78,14 @@ class Settings:
72
78
  )
73
79
  self._odd_and_even_pages_header_footer = enabled
74
80
 
81
+ def _open(self) -> None:
82
+ """Open the document's session before a read or write of it, as every
83
+ member of ``Document`` that touches it does (``Document.create()``
84
+ returns before it opens). ``track_revisions`` needs no session: it
85
+ stays a local flag until one opens."""
86
+ if self._document is not None:
87
+ self._document._ensure_open()
88
+
75
89
  # --- Track changes alias (Athena: forwards to Document.track_revisions) ---
76
90
 
77
91
  @property
@@ -33,6 +33,13 @@ from typing import TYPE_CHECKING, Any, Callable
33
33
 
34
34
  from docx._batching import run_sync
35
35
  from docx._buffer import writes_unapplied
36
+ from docx._proxy import (
37
+ ElementProxyEquality,
38
+ style_definition,
39
+ style_deleted,
40
+ style_element,
41
+ style_renamed,
42
+ )
36
43
  from docx.enum.style import WD_STYLE_TYPE
37
44
  from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING, WD_TAB_ALIGNMENT, WD_TAB_LEADER
38
45
  from docx.shared import Emu, Length, Pt, Twips
@@ -151,7 +158,7 @@ def _style_by_id(session: Any, style_id: object) -> "BaseStyle | None":
151
158
  return _style_of_record(record, session) if record is not None else None
152
159
 
153
160
 
154
- class BaseStyle:
161
+ class BaseStyle(ElementProxyEquality):
155
162
  """Base for all style kinds. Matches python-docx.styles.style.BaseStyle."""
156
163
 
157
164
  def __init__(
@@ -168,6 +175,8 @@ class BaseStyle:
168
175
  self._style_id: str = style_id or name
169
176
  self._type: "WD_STYLE_TYPE" = style_type
170
177
  self._session: "Session | None" = session
178
+ # The definition this proxy stands for, which a rename keeps (equality).
179
+ self._definition: object = style_definition(session, self._style_id)
171
180
  # Writes docx-studio does not take, kept for read-back (see module docstring).
172
181
  self._overrides: dict[str, Any] = {}
173
182
 
@@ -215,6 +224,9 @@ class BaseStyle:
215
224
  self._set_metadata("name", value, name=value)
216
225
 
217
226
  # ---- style_id ----
227
+ def _proxy_element(self) -> tuple[object, ...]:
228
+ return style_element(self)
229
+
218
230
  @property
219
231
  def style_id(self) -> str:
220
232
  return self._overrides.get("style_id", self._style_id)
@@ -239,6 +251,7 @@ class BaseStyle:
239
251
  and server_takes(self._session, "styleIdWrites")
240
252
  ):
241
253
  self._set_metadata("style_id", value, id=value)
254
+ style_renamed(self._session, self._style_id, value)
242
255
  self._style_id = value
243
256
  self._overrides.pop("style_id", None)
244
257
  return
@@ -353,6 +366,7 @@ class BaseStyle:
353
366
  return
354
367
  # Its id as the document holds it: `style_id` may hold a value only this process set.
355
368
  run_sync(self._session.doc.styles.delete({"styleId": self._style_id, "styleType": style_type}))
369
+ style_deleted(self._session, self._style_id)
356
370
  forget_style_table(self._session)
357
371
 
358
372
 
@@ -638,6 +652,16 @@ _MULTIPLE_LINES: dict[WD_LINE_SPACING, int] = {
638
652
  }
639
653
 
640
654
 
655
+ def _alignment_of_jc(jc: object) -> WD_ALIGN_PARAGRAPH | None:
656
+ """The member of a style's own ``w:jc``, as python-docx reads it: None for
657
+ none, and ``ValueError`` for a value it has no member for (``start``,
658
+ ``end``, ``numTab``)."""
659
+ if not isinstance(jc, str) or not jc:
660
+ return None
661
+ member = _ALIGNMENT_OF_JC.get(jc)
662
+ return member if member is not None else WD_ALIGN_PARAGRAPH.from_xml(jc)
663
+
664
+
641
665
  def _alignment_of(value: object) -> WD_ALIGN_PARAGRAPH:
642
666
  """``value`` as a ``WD_ALIGN_PARAGRAPH`` member, as ``Paragraph.alignment`` takes it."""
643
667
  if not isinstance(value, (int, str)):
@@ -675,7 +699,7 @@ def _line_rule_of(own: dict[str, Any]) -> str | None:
675
699
  return "auto" if own.get("lineSpacing") is not None else None
676
700
 
677
701
 
678
- class _StyleParagraphFormat:
702
+ class _StyleParagraphFormat(ElementProxyEquality):
679
703
  """``ParagraphStyle.paragraph_format``: python-docx's ``ParagraphFormat``
680
704
  over a style's own ``w:pPr``.
681
705
 
@@ -694,6 +718,9 @@ class _StyleParagraphFormat:
694
718
  def __init__(self, style: "BaseStyle") -> None:
695
719
  self._style: "BaseStyle" = style
696
720
 
721
+ def _proxy_element(self) -> tuple[object, ...]:
722
+ return style_element(self._style)
723
+
697
724
  def _own(self) -> dict[str, Any] | None:
698
725
  """The style's own paragraph properties from the style table; None
699
726
  when the table carries none (an older docx-studio)."""
@@ -727,7 +754,7 @@ class _StyleParagraphFormat:
727
754
  # ---- alignment ----
728
755
  @property
729
756
  def alignment(self) -> Any:
730
- return self._get("alignment", "alignment", _ALIGNMENT_OF_JC.get)
757
+ return self._get("alignment", "alignment", _alignment_of_jc)
731
758
 
732
759
  @alignment.setter
733
760
  def alignment(self, value: Any) -> None:
@@ -891,6 +918,13 @@ _LIVE_TAB_STOPS: "weakref.WeakKeyDictionary[Any, dict[str, weakref.WeakSet[_Styl
891
918
  weakref.WeakKeyDictionary()
892
919
  )
893
920
 
921
+ # Why a tab stop is out of its style, as python-docx's ``w:tab`` is: taken out
922
+ # of the ``w:tabs`` (``del``, another object of it given a new position), so a
923
+ # new position finds no list to go back into; or in the ``w:tabs`` that
924
+ # ``clear_all`` took out, where a new position still goes.
925
+ _REMOVED = "removed"
926
+ _CLEARED = "cleared"
927
+
894
928
 
895
929
  class _StyleTabStop:
896
930
  """One tab stop of a style's ``w:tabs``, as python-docx's ``TabStop``
@@ -912,7 +946,7 @@ class _StyleTabStop:
912
946
  self._entry: dict[str, Any] = entry
913
947
  self._owner: "_StyleTabStops | None" = owner
914
948
  self._index: int | None = index
915
- self._detached = False
949
+ self._detached: str | None = None
916
950
  if owner is not None and index is not None:
917
951
  owner._track(self)
918
952
 
@@ -928,8 +962,9 @@ class _StyleTabStop:
928
962
  def _change(self, prop: str, entry: dict[str, Any], *, reorder: bool = False) -> None:
929
963
  if self._detached:
930
964
  # python-docx's removed w:tab takes a value (the document does
931
- # not); a new position finds no w:tabs to go back into.
932
- if reorder:
965
+ # not); a new position finds no w:tabs to go back into, but one
966
+ # clear_all took out goes back into the w:tabs it took out.
967
+ if reorder and self._detached != _CLEARED:
933
968
  raise AttributeError("this tab stop is no longer one of the style's")
934
969
  self._entry = entry
935
970
  return
@@ -1019,10 +1054,17 @@ class _StyleTabStops:
1019
1054
  return
1020
1055
  styles.setdefault(self._style.style_id, weakref.WeakSet()).add(stop)
1021
1056
 
1022
- def _moved(self, place: Callable[[int], int | None], entries: dict[int, dict[str, Any]] | None = None) -> None:
1057
+ def _moved(
1058
+ self,
1059
+ place: Callable[[int], int | None],
1060
+ entries: dict[int, dict[str, Any]] | None = None,
1061
+ *,
1062
+ why: str = _REMOVED,
1063
+ ) -> None:
1023
1064
  """After a write: each live tab stop of the style at its new place
1024
1065
  (``place`` of its old one), with its new value where ``entries`` (by
1025
- new place) gives one, or out of the style where ``place`` gives none."""
1066
+ new place) gives one, or out of the style (``why``) where ``place``
1067
+ gives none."""
1026
1068
  try:
1027
1069
  live = (_LIVE_TAB_STOPS.get(self._style._session) or {}).get(self._style.style_id)
1028
1070
  except TypeError:
@@ -1032,7 +1074,7 @@ class _StyleTabStops:
1032
1074
  continue
1033
1075
  new = place(stop._index)
1034
1076
  if new is None:
1035
- stop._detached = True
1077
+ stop._detached = why
1036
1078
  continue
1037
1079
  stop._index = new
1038
1080
  if entries and new in entries:
@@ -1056,19 +1098,24 @@ class _StyleTabStops:
1056
1098
 
1057
1099
  def _replace(self, stop: "_StyleTabStop", entry: dict[str, Any], *, reorder: bool) -> None:
1058
1100
  """Write the style's tab stops with ``stop`` changed to ``entry``: in
1059
- place, or for a new position (``reorder``) taken out and inserted in
1060
- position order, as python-docx's ``TabStop.position`` does (a new
1061
- ``w:tab``, so another object of the old one is out of the style)."""
1101
+ place, or for a new position (``reorder``) inserted where
1102
+ ``insert_tab_in_order`` puts a new one (``stop`` still listed) and
1103
+ taken out of its old place, as python-docx's ``TabStop.position`` does
1104
+ (a new ``w:tab``, so another object of the old one is out of the
1105
+ style); a list out of position order keeps its order around it."""
1062
1106
  stops = list(self._stops())
1063
1107
  at = stop._index
1064
1108
  if at is None or not 0 <= at < len(stops):
1065
1109
  raise ValueError("this tab stop is no longer one of the style's")
1066
1110
  changed = _StyleTabStop(entry, self)
1067
- del stops[at]
1068
- to = at
1069
1111
  if reorder:
1070
- to = next((index for index, kept in enumerate(stops) if kept.position > changed.position), len(stops))
1071
- stops.insert(to, changed)
1112
+ to = next((index for index, kept in enumerate(stops) if changed.position < kept.position), len(stops))
1113
+ stops.insert(to, changed)
1114
+ del stops[at if at < to else at + 1]
1115
+ to = to - 1 if at < to else to
1116
+ else:
1117
+ stops[at] = changed
1118
+ to = at
1072
1119
  self._write(stops)
1073
1120
 
1074
1121
  def place(index: int) -> int | None:
@@ -1078,7 +1125,7 @@ class _StyleTabStops:
1078
1125
  return index + (index >= to)
1079
1126
 
1080
1127
  self._moved(place, {to: entry})
1081
- stop._detached = False
1128
+ stop._detached = None
1082
1129
  stop._index = to
1083
1130
  stop._entry = entry
1084
1131
 
@@ -1127,7 +1174,7 @@ class _StyleTabStops:
1127
1174
  """Remove all of the style's tab stops (its ``w:tabs``), as python-docx does."""
1128
1175
  if self._writes():
1129
1176
  self._write([])
1130
- self._moved(lambda index: None)
1177
+ self._moved(lambda index: None, why=_CLEARED)
1131
1178
  return
1132
1179
  _warn_unwritten(
1133
1180
  "ParagraphStyle.paragraph_format.tab_stops.clear_all",
@@ -13,6 +13,7 @@ import warnings
13
13
  from typing import TYPE_CHECKING
14
14
 
15
15
  from docx._batching import run_sync
16
+ from docx._proxy import ElementProxyEquality
16
17
  from docx.enum.style import WD_STYLE_TYPE
17
18
  from docx.styles import BabelFish
18
19
  from docx.styles.latent import LatentStyles, PendingLatentStylesReadWarning
@@ -110,13 +111,16 @@ def _style_id_from_name(name: str) -> str:
110
111
  return _SPECIAL_STYLE_IDS.get(name, name.replace(" ", ""))
111
112
 
112
113
 
113
- class Styles:
114
+ class Styles(ElementProxyEquality):
114
115
  """Collection of styles. Iterable, len, __getitem__."""
115
116
 
116
117
  def __init__(self, *, session: "Session") -> None:
117
118
  self._session: "Session" = session
118
119
  self._added: dict[str, BaseStyle] = {}
119
120
 
121
+ def _proxy_element(self) -> tuple[object, ...]:
122
+ return ("w:styles", self._session)
123
+
120
124
  def _all(self) -> list[BaseStyle]:
121
125
  from docx._table_styles import BUILTIN_TABLE_STYLE_IDS
122
126
  from docx.styles._table import builtin_style_id, builtin_style_name, style_table