athena-python-docx 0.40.0__tar.gz → 0.42.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 (498) hide show
  1. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/AGENTS.md +91 -19
  2. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/PKG-INFO +1 -1
  3. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/__init__.py +1 -1
  4. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/comments.py +62 -1
  5. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/styles/_table.py +67 -7
  6. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/paragraph.py +41 -11
  7. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/pyproject.toml +1 -1
  8. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/fake_session.py +5 -0
  9. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/fixture_scripts.py +359 -0
  10. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/intentional_deviations.json +47 -7
  11. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_comments.py +132 -0
  12. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_hyperlink_coalescing.py +43 -0
  13. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_rendered_page_breaks.py +24 -0
  14. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_table_style_objects.py +58 -0
  15. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/uv.lock +1 -1
  16. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/.gitignore +0 -0
  17. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/CLAUDE.md +0 -0
  18. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/DOCX_EXEC_LAB.md +0 -0
  19. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/README.md +0 -0
  20. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_athena_extension.py +0 -0
  21. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_batching.py +0 -0
  22. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_buffer.py +0 -0
  23. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_capabilities.py +0 -0
  24. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_citations.py +0 -0
  25. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_execution.py +0 -0
  26. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_http.py +0 -0
  27. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_http_doc.py +0 -0
  28. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_image_utils.py +0 -0
  29. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_postproc.py +0 -0
  30. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_proxy.py +0 -0
  31. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_ptc.py +0 -0
  32. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_references.py +0 -0
  33. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_run_order.py +0 -0
  34. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_table_styles.py +0 -0
  35. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_timeouts.py +0 -0
  36. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_tracked.py +0 -0
  37. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/_xml_text.py +0 -0
  38. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/api.py +0 -0
  39. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/blkcntnr.py +0 -0
  40. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/bookmarks.py +0 -0
  41. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/charts.py +0 -0
  42. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/client.py +0 -0
  43. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/commands.py +0 -0
  44. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/document.py +0 -0
  45. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/drawing/__init__.py +0 -0
  46. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/__init__.py +0 -0
  47. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/base.py +0 -0
  48. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/dml.py +0 -0
  49. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/section.py +0 -0
  50. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/shape.py +0 -0
  51. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/style.py +0 -0
  52. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/table.py +0 -0
  53. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/enum/text.py +0 -0
  54. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/errors.py +0 -0
  55. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/exceptions.py +0 -0
  56. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/fields.py +0 -0
  57. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/footnotes.py +0 -0
  58. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/image/__init__.py +0 -0
  59. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/image/exceptions.py +0 -0
  60. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/image/image.py +0 -0
  61. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/math.py +0 -0
  62. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/opc/__init__.py +0 -0
  63. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/opc/coreprops.py +0 -0
  64. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/oxml/__init__.py +0 -0
  65. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/revisions.py +0 -0
  66. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/sdt.py +0 -0
  67. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/section.py +0 -0
  68. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/session.py +0 -0
  69. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/settings.py +0 -0
  70. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/shape.py +0 -0
  71. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/shared.py +0 -0
  72. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/styles/__init__.py +0 -0
  73. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/styles/latent.py +0 -0
  74. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/styles/style.py +0 -0
  75. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/styles/styles.py +0 -0
  76. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/table.py +0 -0
  77. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/__init__.py +0 -0
  78. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/font.py +0 -0
  79. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/hyperlink.py +0 -0
  80. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/pagebreak.py +0 -0
  81. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/parfmt.py +0 -0
  82. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/run.py +0 -0
  83. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/text/tabstops.py +0 -0
  84. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/toc.py +0 -0
  85. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/docx/typing.py +0 -0
  86. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/docx_exec_lab.py +0 -0
  87. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  88. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  89. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/docx_exec_lab_server.py +0 -0
  90. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/dump_wire_fixtures.py +0 -0
  91. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/release.sh +0 -0
  92. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/round_trip_smoke.py +0 -0
  93. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/smoke_test_block_not_found.py +0 -0
  94. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/scripts/validate_find_replace_asset.py +0 -0
  95. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/__init__.py +0 -0
  96. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/conftest.py +0 -0
  97. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/METHODOLOGY.md +0 -0
  98. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/README.md +0 -0
  99. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/__init__.py +0 -0
  100. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/__init__.py +0 -0
  101. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/agent_documents.py +0 -0
  102. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
  103. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
  104. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
  105. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
  106. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
  107. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/picture_runs.py +0 -0
  108. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
  109. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/return_types.py +0 -0
  110. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
  111. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
  112. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe_cases.py +0 -0
  113. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ab_probe_runner.py +0 -0
  114. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/auto_gen_cases.py +0 -0
  115. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/binary_round_trip.py +0 -0
  116. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/cases.py +0 -0
  117. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/complex_cases.py +0 -0
  118. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/coverage_report.py +0 -0
  119. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/extract.py +0 -0
  120. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/extreme_cases.py +0 -0
  121. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/README.md +0 -0
  122. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  123. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  124. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  125. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  126. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  127. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/local_runner.py +0 -0
  128. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/mega_cases.py +0 -0
  129. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshot.py +0 -0
  130. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  131. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  132. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  133. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  134. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  135. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  136. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  137. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  138. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  139. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  140. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  141. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  142. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  143. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  144. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  145. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  146. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  147. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  148. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  149. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  150. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  151. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  152. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  153. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  154. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  155. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  156. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  157. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  158. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  159. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  160. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  161. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  162. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  163. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  164. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  165. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  166. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  167. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  168. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  169. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  170. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  171. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  172. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  173. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  174. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  175. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  176. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  177. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  178. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  179. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  180. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  181. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  182. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  183. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  184. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  185. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  186. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  187. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  188. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  189. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  190. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  191. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  192. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  193. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  194. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  195. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  196. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  197. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  198. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  199. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  200. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  201. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  202. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  203. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  204. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  205. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  206. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  207. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  208. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  209. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  210. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  211. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  212. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  213. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  214. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  215. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  216. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  217. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  218. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  219. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  220. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  221. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  222. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  223. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  224. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  225. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  226. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  227. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  228. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  229. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  230. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  231. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  232. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  233. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  234. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  235. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  236. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  237. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  238. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  239. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  240. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  241. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  242. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  243. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  244. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  245. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  246. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  247. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  248. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  249. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  250. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  251. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  252. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  253. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  254. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  255. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  256. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  257. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  258. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  259. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  260. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  261. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  262. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  263. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  264. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  265. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  266. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  267. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  268. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  269. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  270. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  271. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  272. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  273. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  274. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  275. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  276. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  277. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  278. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  279. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  280. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  281. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  282. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/ours_spec.json +0 -0
  283. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/parity_crawl.py +0 -0
  284. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/parity_diff.json +0 -0
  285. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/real_world_cases.py +0 -0
  286. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/round_trip_tests.py +0 -0
  287. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/stock_spec.json +0 -0
  288. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  289. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fixtures/field_reads.json +0 -0
  290. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fixtures/note_reference_reads.json +0 -0
  291. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fixtures/ruby_reads.json +0 -0
  292. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/fixtures/symbol_reads.json +0 -0
  293. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/__init__.py +0 -0
  294. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/baseline.json +0 -0
  295. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/reader.py +0 -0
  296. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/runner.py +0 -0
  297. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/sdk_driver.py +0 -0
  298. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/stock_driver.py +0 -0
  299. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/live/test_live_runner.py +0 -0
  300. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/README.md +0 -0
  301. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/__init__.py +0 -0
  302. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/baseline_gaps.json +0 -0
  303. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/compare.py +0 -0
  304. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/introspect.py +0 -0
  305. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  306. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/reports/gap_report.json +0 -0
  307. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/run_parity.py +0 -0
  308. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/snapshots/athena_latest.json +0 -0
  309. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  310. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/parity/test_parity_gap.py +0 -0
  311. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_add_section.py +0 -0
  312. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_add_section_extract_items.py +0 -0
  313. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_alignment_values.py +0 -0
  314. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  315. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_athena_extensions_contract.py +0 -0
  316. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_athena_extensions_registry.py +0 -0
  317. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_batch_chunking.py +0 -0
  318. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_batching_perf.py +0 -0
  319. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_battery_cases.py +0 -0
  320. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_block_not_found_error.py +0 -0
  321. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_buffer.py +0 -0
  322. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  323. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_add_table_not_supported.py +0 -0
  324. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_borders_spec.py +0 -0
  325. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_fastpath_runs.py +0 -0
  326. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  327. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  328. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_inner_format_stash.py +0 -0
  329. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  330. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_inner_run_guard.py +0 -0
  331. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_merge.py +0 -0
  332. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_nested_tables.py +0 -0
  333. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_paragraphs_listed.py +0 -0
  334. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  335. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_cell_text_replace_semantics.py +0 -0
  336. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_citations.py +0 -0
  337. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_collapsed_range_format.py +0 -0
  338. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_color_format_theme.py +0 -0
  339. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_command_dataclasses.py +0 -0
  340. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_commands.py +0 -0
  341. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_comment_paragraphs.py +0 -0
  342. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_comments_first_read.py +0 -0
  343. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_content_control_value.py +0 -0
  344. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_core_properties.py +0 -0
  345. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_asset_id_property.py +0 -0
  346. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_clear.py +0 -0
  347. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_create.py +0 -0
  348. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_create_from_template.py +0 -0
  349. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_factory_validation.py +0 -0
  350. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_document_settings_session_open.py +0 -0
  351. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_docx_exec_lab.py +0 -0
  352. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_docx_exec_lab_server.py +0 -0
  353. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_drawing_image.py +0 -0
  354. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  355. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_empty_hyperlinks.py +0 -0
  356. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_enum_parity.py +0 -0
  357. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_execution_scope.py +0 -0
  358. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_export_docx_clean.py +0 -0
  359. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_export_rescue_anchors.py +0 -0
  360. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  361. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_field_refresh.py +0 -0
  362. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_field_runs.py +0 -0
  363. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_find_replace_session_open.py +0 -0
  364. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_flushed_write_failures.py +0 -0
  365. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_http_transport.py +0 -0
  366. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_image_url_data_uri.py +0 -0
  367. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_inline_page_break.py +0 -0
  368. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_inline_shape_alt_text.py +0 -0
  369. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_inline_shape_size.py +0 -0
  370. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_inline_shape_type.py +0 -0
  371. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_inline_shapes_floating.py +0 -0
  372. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_insert_deferred.py +0 -0
  373. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_iter_inner_content.py +0 -0
  374. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_latent_style_writes.py +0 -0
  375. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_line_clear_break.py +0 -0
  376. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_list_styles.py +0 -0
  377. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_listed_paragraph_reads.py +0 -0
  378. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_literal_no_break_hyphens.py +0 -0
  379. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_literal_soft_hyphens.py +0 -0
  380. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_merged_cell_identity.py +0 -0
  381. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  382. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_merged_cells.py +0 -0
  383. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_missing_modules.py +0 -0
  384. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_nested_table_refused.py +0 -0
  385. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  386. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_oxml_shim.py +0 -0
  387. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_page_break.py +0 -0
  388. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_paragraph_delete.py +0 -0
  389. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_paragraph_indent_reads.py +0 -0
  390. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  391. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_paragraph_text_empty_run.py +0 -0
  392. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_paragraph_text_len_cache.py +0 -0
  393. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_parfmt_clears.py +0 -0
  394. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_parity_misc.py +0 -0
  395. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_parity_round2.py +0 -0
  396. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_partial_failure_cascade.py +0 -0
  397. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  398. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_phase_a_behavior.py +0 -0
  399. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_phase_b_headers_footers.py +0 -0
  400. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_phase_c_tables.py +0 -0
  401. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_positional_cell_id.py +0 -0
  402. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  403. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  404. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_postproc_ref_restore.py +0 -0
  405. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_pr19766_review_fixes.py +0 -0
  406. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_proxy_equality.py +0 -0
  407. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_ptc.py +0 -0
  408. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_python_docx_api_parity.py +0 -0
  409. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_read_run_ranges.py +0 -0
  410. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_repeated_node_read.py +0 -0
  411. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_restart_numbering.py +0 -0
  412. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_revisions.py +0 -0
  413. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_round_trip_smoke_script.py +0 -0
  414. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  415. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_add_picture_anchor.py +0 -0
  416. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_break_inner_content.py +0 -0
  417. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_edges.py +0 -0
  418. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_formatting_wire.py +0 -0
  419. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_identity.py +0 -0
  420. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_later_runs.py +0 -0
  421. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_mark_inheritance.py +0 -0
  422. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_page_number_blocks.py +0 -0
  423. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_text_python_docx.py +0 -0
  424. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  425. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_run_unmodeled_toggles.py +0 -0
  426. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_sdk_reads_served.py +0 -0
  427. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_section_read_lengths.py +0 -0
  428. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_sections_empty_list.py +0 -0
  429. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  430. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_add_picture.py +0 -0
  431. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_add_run.py +0 -0
  432. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  433. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  434. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_comments_get.py +0 -0
  435. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_document_audit.py +0 -0
  436. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_document_element.py +0 -0
  437. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_enum_section.py +0 -0
  438. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_font_audit.py +0 -0
  439. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_header_footer.py +0 -0
  440. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_hyperlink.py +0 -0
  441. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_inline_shape.py +0 -0
  442. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  443. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_misc.py +0 -0
  444. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  445. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  446. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  447. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_parfmt.py +0 -0
  448. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  449. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_add_break.py +0 -0
  450. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  451. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_style.py +0 -0
  452. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  453. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_text.py +0 -0
  454. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_run_underline.py +0 -0
  455. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_section_audit.py +0 -0
  456. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  457. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_section_onoff.py +0 -0
  458. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_settings.py +0 -0
  459. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_shared_audit.py +0 -0
  460. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_style.py +0 -0
  461. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_styles.py +0 -0
  462. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_table_audit.py +0 -0
  463. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_table_cell.py +0 -0
  464. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  465. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_silent_stub_table_layout.py +0 -0
  466. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_smoke_integration.py +0 -0
  467. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_acceptance.py +0 -0
  468. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_delete.py +0 -0
  469. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_font.py +0 -0
  470. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_formatting_writes.py +0 -0
  471. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_metadata_writes.py +0 -0
  472. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_names.py +0 -0
  473. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_resolution.py +0 -0
  474. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_setters_contract.py +0 -0
  475. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_tab_stops.py +0 -0
  476. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_style_tab_stops_read.py +0 -0
  477. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  478. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_tab_stop_writes.py +0 -0
  479. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_add_row_grid_row.py +0 -0
  480. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_anchors.py +0 -0
  481. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_clears.py +0 -0
  482. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_direction.py +0 -0
  483. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_length_reads.py +0 -0
  484. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_listing_reads.py +0 -0
  485. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_read_reuse.py +0 -0
  486. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_set_cell_perf.py +0 -0
  487. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_table_style_id_resolution.py +0 -0
  488. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_temporarily_unavailable.py +0 -0
  489. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_text_control_characters.py +0 -0
  490. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_tracked_revisions_offsets.py +0 -0
  491. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_unmapped_alignment_reads.py +0 -0
  492. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_uv_lock_version.py +0 -0
  493. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  494. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_versioned_read_reuse.py +0 -0
  495. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_wire_contract.py +0 -0
  496. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_xml_attr_guard.py +0 -0
  497. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_xml_incompatible_text.py +0 -0
  498. {athena_python_docx-0.40.0 → athena_python_docx-0.42.0}/tests/test_zod_wire_contract.py +0 -0
@@ -1080,6 +1080,20 @@ architecture or a DOCX Studio constraint:
1080
1080
  name the document lacks raises `KeyError` unless docx-studio holds Word's
1081
1081
  definition of it (`BUILTIN_CHARACTER_STYLE_NAMES` in
1082
1082
  `docx/styles/_table.py`: `"Strong"`, `"Intense Emphasis"`, `"Book Title"`…).
1083
+ A character style the uploaded file's runs name without defining it (a
1084
+ generator's links naming `Hyperlink`) reads as the default character
1085
+ style, as python-docx reads it, and the export leaves it undefined, so an
1086
+ unedited download is the file (owner decision, 2026-10-26, #46935 A2).
1087
+ The editor and the server's PDFs still draw those runs in Word's built-in
1088
+ style, blue and underlined. docx-studio records the import's list, and a
1089
+ format that gives a run one of those styles (`run.style = "Hyperlink"`):
1090
+ from then on the export defines it, as Word adds a style's definition when
1091
+ it is applied, and `Info`'s `undefinedRunStyleIds` no longer lists it, so
1092
+ every session reads its runs as the built-in; the SDK asks `Info` again
1093
+ after such a write. An edit in the editor that copies such a run (a paste,
1094
+ the format painter) leaves the style undefined. A room imported before
1095
+ the record (no `undefinedRunStyleIds`) reads them as the built-in and its
1096
+ export adds the definition, as before.
1083
1097
  `Document.add_table(style=)` and `Paragraph.add_run(style=)` resolve the
1084
1098
  style before creating anything, so a rejected style leaves the document
1085
1099
  untouched; python-docx raises after adding the table or run to its
@@ -1223,7 +1237,9 @@ architecture or a DOCX Studio constraint:
1223
1237
  offsets in a run's text (`literalCharacters`), which `_word_text` reads as
1224
1238
  written; a docx-studio that sends none reads each as the element, as before.
1225
1239
  The export writes them back in a `w:t`, and text a script writes holds them
1226
- as upstream writes it, in a `w:t`.
1240
+ as upstream writes it, in a `w:t`. `Document.find_replace` keeps each hyphen
1241
+ the replacement shares with the match as the match held it, and writes any
1242
+ other in a `w:t`, as upstream writes text.
1227
1243
 
1228
1244
  - **`CoreProperties.modified` is the time of the last save.** The asset is a
1229
1245
  live Word document, and docx-studio stamps `dcterms:modified` when it saves
@@ -1256,6 +1272,30 @@ architecture or a DOCX Studio constraint:
1256
1272
  changes; the owner may overrule it. Recorded in
1257
1273
  `tests/parity/intentional_deviations.json` (`live_deviations`).
1258
1274
 
1275
+ - **The inner link of a nested link reads with its text.** A `w:hyperlink`
1276
+ inside another (the duplicate wrapper Word writes around a pasted link,
1277
+ each with a relationship of its own; 3 of 6,826 customer uploads) reads
1278
+ its inner link's runs in `Hyperlink.runs` / `text`, `Paragraph.text` and
1279
+ `iter_inner_content()`, as Word shows them; upstream reads only a link's
1280
+ own `w:r` children, so the inner text is invisible to it and
1281
+ `p.text = p.text.replace(...)` would delete it unseen. The same choice as
1282
+ inline wrappers and tracked changes. Owner decision, 2026-10-26 (#46935,
1283
+ A1). Recorded in `tests/parity/intentional_deviations.json`
1284
+ (`live_deviations`) with the synthetic fixture `hyperlinks-nested`.
1285
+
1286
+ - **An emoji written as `w16se:symEx` reads as its run's text.** Word 2016
1287
+ writes an emoji as the run's `mc:AlternateContent`: an `mc:Choice
1288
+ Requires="w16se"` holding `w16se:symEx` (its font and character), and an
1289
+ `mc:Fallback` holding a `w:t` of the emoji (1 of 6,826 customer uploads).
1290
+ `Run.text`, `iter_inner_content()` and the paragraph's text hold the emoji,
1291
+ as Word shows it; upstream reads only a run's own `w:t` children and reads
1292
+ `""`, so a script rewriting the paragraph would delete the emoji unseen.
1293
+ An edited paragraph's export writes the emoji in a plain `w:t`, without
1294
+ the `w16se:symEx` choice, so upstream then reads it there too. Owner
1295
+ decision, 2026-10-26 (#46935, A5). Recorded in
1296
+ `tests/parity/intentional_deviations.json` (`live_deviations`) with the
1297
+ synthetic fixture `symbols-emoji-alternate-content`.
1298
+
1259
1299
  - **Two things a source writes that the model holds otherwise read as the
1260
1300
  model holds them** (2026-10-22 SDK live parity run over 398 customer
1261
1301
  documents). Each is recorded in
@@ -1292,24 +1332,19 @@ architecture or a DOCX Studio constraint:
1292
1332
  which the editor draws it with, where upstream reads the default table
1293
1333
  style; reading the default would change how such tables draw. The export
1294
1334
  leaves the style undefined, as the source has it: an unedited download of
1295
- a document imported since is the source's bytes (owner, 2026-10-23). The read is kept until Word can be
1296
- checked, as no Word probe can be made on the machine that recorded it
1297
- (`tables-undefined-style`).
1335
+ a document imported since is the source's bytes (owner, 2026-10-23). The read is kept
1336
+ (`tables-undefined-style`): checked on 2026-10-24 against the one sample
1337
+ document's Word PDF, whose tables draw alike under either style (empty
1338
+ paragraph defaults, the tables' own borders and margins) and match the
1339
+ editor's Table Grid layout, so no corpus document yet tells the two apart.
1298
1340
  - A package with no styles part (1 document) reads Word's built-in styles,
1299
1341
  which the editor gives it, where upstream reads its own default template's
1300
1342
  (`styles-part-absent`). Confirmed by the owner, 2026-10-23.
1301
1343
 
1302
- - **Two more reads follow the model where python-docx reads the source**
1303
- (2026-10-22 SDK live parity run over 398 customer documents, round 3). Each is
1344
+ - **One more read follows the model where python-docx reads the source**
1345
+ (2026-10-22 SDK live parity run over 398 customer documents, round 3). It is
1304
1346
  recorded in `tests/parity/intentional_deviations.json` (`live_deviations`)
1305
1347
  with a synthetic fixture:
1306
- - A comment whose range ends between paragraphs (`w:commentRangeEnd` a
1307
- child of `w:body`; 1 document, 11 of 6,826 uploads) reads its reference
1308
- run at the end of the last paragraph its mark covers, where the export
1309
- writes it from the model, where upstream reads it in the paragraph after
1310
- the range end: the model holds a range as a mark on its text and no range
1311
- end between paragraphs (`comments-range-end-between-paragraphs`).
1312
- Confirmed by the owner, 2026-10-23.
1313
1348
  - A comment's annotation reference run that names no character style
1314
1349
  (1 document, 13 of 6,826 uploads) reads in the CommentReference style, in
1315
1350
  which the export writes every comment's annotation run when it writes the
@@ -1317,6 +1352,25 @@ architecture or a DOCX Studio constraint:
1317
1352
  run as an empty run nothing tells from another
1318
1353
  (`comments-annotation-ref-unstyled`). Confirmed by the owner, 2026-10-23.
1319
1354
 
1355
+ A comment whose range ends between paragraphs (`w:commentRangeEnd` a child
1356
+ of `w:body`; 1 document, 11 of 6,826 uploads) is no longer a deviation, with
1357
+ the other comments whose reference run stands apart from the text their
1358
+ range marks: one over links alone in several paragraphs or over a picture or
1359
+ an object alone, which the model holds no range for, one that ends in a
1360
+ paragraph holding none of its text, and one whose run follows a field's end
1361
+ run. The import records where the source body holds each reference run and
1362
+ range end (`commentReferenceRunPlaces`: the paragraph and how many of its
1363
+ runs come before it), the paragraphs whose text it marks for the comment,
1364
+ and the fingerprint of each body block that holds them. While those blocks
1365
+ are as imported and the comment marks the same paragraphs, the run reads
1366
+ where the source holds it, where the export keeps the blocks' source XML,
1367
+ and a reply added since reads beside the comment's range end, where the
1368
+ export writes it (`comments-range-end-between-paragraphs`,
1369
+ `comments-range-over-links`, `comments-range-end-without-text`,
1370
+ `comments-range-over-object`). A block an edit changed, a comment moved to
1371
+ new text, and a room imported before the record read where the model places
1372
+ the run, as before.
1373
+
1320
1374
  A third, runs of one formatting read and exported joined after a run write
1321
1375
  in a paragraph with a link, an inline content control, an equation or a
1322
1376
  field beside a picture, is no longer a deviation (the owner asked for it to
@@ -1324,14 +1378,16 @@ architecture or a DOCX Studio constraint:
1324
1378
  `add_run`, `add_text`) carries the records the read takes of such a
1325
1379
  paragraph's runs (`_writtenRunRecords`), each `w:r` kept with the written
1326
1380
  run changed as python-docx changes it, and the export writes the paragraph
1327
- from them. A write the records cannot describe (a format of a field's runs,
1328
- a write across a field, a run the offsets cannot tell from an empty one
1329
- beside it) leaves the paragraph as before: a link paragraph's kept content,
1330
- else the runs its marks make. Fixture scripts
1381
+ from them. A format of one of a field's own runs is carried too, into the
1382
+ field's record (2026-10-24, #46477). A write the records cannot describe (a
1383
+ write across a field, a field's result written, a run the offsets cannot
1384
+ tell from an empty one beside it) leaves the paragraph as before: a link
1385
+ paragraph's kept content, else the runs its marks make. Fixture scripts
1331
1386
  `fixture-links-run-write-keeps-runs`, `fixture-links-run-writes`,
1332
1387
  `fixture-content-controls-inline-run-writes`,
1333
- `fixture-equations-beside-runs-run-writes` and
1334
- `fixture-fields-beside-pictures-run-writes`.
1388
+ `fixture-equations-beside-runs-run-writes`,
1389
+ `fixture-fields-beside-pictures-run-writes` and
1390
+ `fixture-fields-beside-pictures-field-run-formats`.
1335
1391
 
1336
1392
  - **A citation link Athena added reads as its text, as the export writes it**
1337
1393
  (owner decision #40122). Athena's citation flow stamps the links it writes
@@ -1416,6 +1472,22 @@ architecture or a DOCX Studio constraint:
1416
1472
  exported file. Against a docx-studio that predates `fieldRun` reads, a
1417
1473
  field reads as no runs and no text, as before (`tests/test_field_runs.py`).
1418
1474
 
1475
+ - **A header or footer run holding text beside a whole field reads as more
1476
+ runs.** A generator writes a page number as one `w:r` holding `Page ` and a
1477
+ `PAGE` field's begin, code, separate and end characters (1 of 6,826
1478
+ customer uploads). Upstream reads one run, `Page `. The import cuts that
1479
+ `w:r` into a run of the text and the field's own run (and a run of any text
1480
+ after the field; `RunParseOptions.cutRunsAtFields`), so the paragraph's
1481
+ text reads as upstream's and the editor and the server's PDFs draw it;
1482
+ before, the field took the whole run and the text was lost, from the reads
1483
+ and from an edited footer's export. `paragraph.runs` holds the extra runs,
1484
+ and an edited paragraph's export writes them as runs of their own: a
1485
+ cosmetic run split. A body run of that shape is still read the old way, as
1486
+ its room stores what its import read. Owner decision, 2026-10-26 (#46935,
1487
+ A4). Recorded in `tests/parity/intentional_deviations.json`
1488
+ (`live_deviations`) with the synthetic fixture
1489
+ `footers-text-and-field-one-run`.
1490
+
1419
1491
  - **A run that holds a page number block refuses a tracked whole-run format
1420
1492
  and two text writes.** A page number block (`w:pgNum`) reads as a run with
1421
1493
  no text, and a run that holds text and blocks (or two blocks) reads as
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.40.0
3
+ Version: 0.42.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.40.0"
9
+ __version__ = "0.42.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -40,6 +40,7 @@ from docx._batching import run_sync
40
40
  from docx._buffer import writes_unapplied
41
41
  from docx.blkcntnr import BlockItemContainer
42
42
  from docx.errors import DocxError, NotFoundError
43
+ from docx.text.paragraph import _buffer_writes
43
44
 
44
45
  if TYPE_CHECKING:
45
46
  from collections.abc import Iterator, Sequence
@@ -186,6 +187,35 @@ def _coerce_timestamp(raw: object) -> datetime | None:
186
187
  return None
187
188
 
188
189
 
190
+ def _word_date(raw: object) -> datetime | None:
191
+ """A comment's ``w:date`` as python-docx 1.2.0's ``Comment.timestamp``
192
+ reads it (``ST_DateTime.convert_from_xml``): with a trailing ``Z``, a time
193
+ in UTC; with an offset, a time in that zone; without either, a time in no
194
+ zone, as Word writes the author's local time; one it cannot parse, the
195
+ epoch in UTC. ``None`` for a comment with no ``w:date``."""
196
+ if not isinstance(raw, str):
197
+ return None
198
+
199
+ def parse(text: str) -> datetime:
200
+ if text.endswith("Z"):
201
+ try:
202
+ return datetime.strptime(text, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc)
203
+ except ValueError:
204
+ return datetime.strptime(text, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
205
+ try:
206
+ return datetime.fromisoformat(text)
207
+ except ValueError:
208
+ try:
209
+ return datetime.strptime(text, "%Y-%m-%dT%H:%M:%S.%f")
210
+ except ValueError:
211
+ return datetime.strptime(text, "%Y-%m-%dT%H:%M:%S")
212
+
213
+ try:
214
+ return parse(raw)
215
+ except Exception:
216
+ return datetime(1970, 1, 1, tzinfo=timezone.utc)
217
+
218
+
189
219
  # docx-studio's caps (``MAX_COMMENT_AUTHOR_LENGTH`` /
190
220
  # ``MAX_COMMENT_INITIALS_LENGTH`` in apps/api/src/commands/types.ts), in
191
221
  # UTF-16 code units as the server counts them.
@@ -274,7 +304,7 @@ def _created_comment_info(
274
304
  }
275
305
  stored = result.get("comment") if isinstance(result, dict) else None
276
306
  if isinstance(stored, dict):
277
- for key in ("creatorName", "initials", "createdTime"):
307
+ for key in ("creatorName", "initials", "createdTime", "wordDate"):
278
308
  if key in stored:
279
309
  info[key] = stored[key]
280
310
  return info
@@ -291,6 +321,10 @@ class Comment(BlockItemContainer):
291
321
  ) -> None:
292
322
  self._session: "Session" = session
293
323
  self._info: dict = dict(info or {})
324
+ # The command buffer's ``writes`` count the info was read at: a later
325
+ # write (to the comment's paragraphs or runs, its replies' root, or
326
+ # anything the export writes it anew for) may change its ``w:date``.
327
+ self._dated_at: int | None = _buffer_writes(session)
294
328
 
295
329
  # ---- identity / metadata ----
296
330
  @property
@@ -336,6 +370,29 @@ class Comment(BlockItemContainer):
336
370
 
337
371
  @property
338
372
  def timestamp(self) -> datetime | None:
373
+ """The ``w:date`` docx-studio says the export writes for the comment
374
+ (``wordDate``), read as python-docx reads it: the source's own for a
375
+ comment no write changed, which Word writes in the author's local time
376
+ with no zone. A docx-studio that does not say gives the comment's
377
+ time in UTC (``createdTime``). After a write since the comment was
378
+ read (its text, a paragraph added to it, an edit of its paragraphs or
379
+ runs, or any other, which may make the export write it anew), it reads
380
+ the comment again; a read that fails is tried again at the next."""
381
+ if self._info.get("_wordDateStale") or _buffer_writes(self._session) != self._dated_at:
382
+ try:
383
+ fresh: object = run_sync(self._session.doc.comments.get({"id": self._id}))
384
+ except NotFoundError as exc:
385
+ if writes_unapplied(exc):
386
+ raise
387
+ fresh = None
388
+ if isinstance(fresh, dict):
389
+ for key in ("wordDate", "createdTime"):
390
+ if key in fresh:
391
+ self._info[key] = fresh[key]
392
+ self._info.pop("_wordDateStale", None)
393
+ self._dated_at = _buffer_writes(self._session)
394
+ if "wordDate" in self._info:
395
+ return _word_date(self._info.get("wordDate"))
339
396
  return _coerce_timestamp(self._info.get("createdTime"))
340
397
 
341
398
  # ---- body ----
@@ -363,6 +420,8 @@ class Comment(BlockItemContainer):
363
420
 
364
421
  run_sync(self._session.doc.comments.patch({"id": self._id, "text": value}))
365
422
  self._info["text"] = value
423
+ # The export writes the comment anew, with the date its record holds.
424
+ self._info["_wordDateStale"] = True
366
425
  # CommentsPatch is a Command type — referenced for clarity / parity
367
426
  # with the bus dispatch path.
368
427
  del CommentsPatch
@@ -459,6 +518,8 @@ class Comment(BlockItemContainer):
459
518
  node_id = result.get("nodeId") if isinstance(result, dict) else None
460
519
  if not isinstance(node_id, str) or not node_id:
461
520
  raise CommentsNotImplementedError("Paragraphs added to comments")
521
+ # The export writes the comment anew, with the date its record holds.
522
+ self._info["_wordDateStale"] = True
462
523
  paragraph = Paragraph(session=self._session, node_id=node_id, node_type="paragraph", text_len=len(text))
463
524
  if style is not None:
464
525
  paragraph.style = style
@@ -159,6 +159,15 @@ _latent: "weakref.WeakKeyDictionary[Any, dict[str, Any] | None]" = weakref.WeakK
159
159
  #: Each session's paragraph style ids its document's source names without
160
160
  #: defining them, as ``Info`` reports them (``undefinedStyleIds``).
161
161
  _undefined: "weakref.WeakKeyDictionary[Any, frozenset[str]]" = weakref.WeakKeyDictionary()
162
+ #: Each session's character style ids the runs of its uploaded file name
163
+ #: without the file defining them and no write has given a run, as ``Info``
164
+ #: reports them (``undefinedRunStyleIds``; none from a room imported before the
165
+ #: record): the export leaves them undefined.
166
+ _undefined_runs: "weakref.WeakKeyDictionary[Any, frozenset[str]]" = weakref.WeakKeyDictionary()
167
+ #: Sessions whose script gave a run one of ``_undefined_runs``: docx-studio
168
+ #: records the write (the export defines the style from then on), so the next
169
+ #: read of such a style asks ``Info`` again, after the write.
170
+ _runs_restyled: "weakref.WeakSet[Any]" = weakref.WeakSet()
162
171
 
163
172
 
164
173
  def _records(info: object) -> tuple[StyleRecord, ...] | None:
@@ -229,6 +238,12 @@ def style_table(session: Any) -> tuple[StyleRecord, ...] | None:
229
238
  if isinstance(undefined_ids, list)
230
239
  else frozenset()
231
240
  )
241
+ undefined_run_ids: object = info.get("undefinedRunStyleIds") if isinstance(info, dict) else None
242
+ _undefined_runs[session] = (
243
+ frozenset(i for i in undefined_run_ids if isinstance(i, str))
244
+ if isinstance(undefined_run_ids, list)
245
+ else frozenset()
246
+ )
232
247
  _stale.discard(session)
233
248
  # A server that showed it writes styles still does once deletes leave its
234
249
  # table without the entries that told: the signal holds for the session.
@@ -577,11 +592,15 @@ def style_of(
577
592
  default style, else None.
578
593
 
579
594
  A Word built-in the document does not define reads back as that built-in,
580
- as ``style_id_for`` lets it be set. A document without styles reads its
581
- defaults as Word's, as python-docx's default ``styles.xml`` gives them.
582
- Without a style table: the stored style as given, else Word's default.
583
- The style reads the definition it was found as (its record), as
584
- python-docx's wraps that ``w:style``.
595
+ as ``style_id_for`` lets it be set; not a character style the runs of the
596
+ uploaded file already named without defining it and no write has given a
597
+ run (``Info``'s ``undefinedRunStyleIds``), which python-docx reads as the
598
+ default character style and the export leaves undefined. A document
599
+ without styles reads its defaults as Word's,
600
+ as python-docx's default ``styles.xml`` gives them. Without a style table:
601
+ the stored style as given, else Word's default. The style reads the
602
+ definition it was found as (its record), as python-docx's wraps that
603
+ ``w:style``.
585
604
  """
586
605
  from docx.styles.style import _style_of_record
587
606
 
@@ -592,7 +611,12 @@ def style_of(
592
611
  name, style_id = builtin or (BabelFish.internal2ui(stored_style_id), stored_style_id)
593
612
  return _new_style(session, name, style_id, style_type)
594
613
  record = first_of_id(table or (), stored_style_id) if stored_style_id else None
595
- if record is None and builtin is not None and _defined_builtin(style_type, builtin[1]):
614
+ if (
615
+ record is None
616
+ and builtin is not None
617
+ and _defined_builtin(style_type, builtin[1])
618
+ and not _file_left_undefined(session, stored_style_id, style_type)
619
+ ):
596
620
  return _new_style(session, *builtin, style_type)
597
621
  if record is None or record.type != style_type:
598
622
  record = default_style(table, style_type) if table else None
@@ -601,6 +625,39 @@ def style_of(
601
625
  return _style_of_record(record, session)
602
626
 
603
627
 
628
+ def _file_left_undefined(session: Any, style_id: str | None, style_type: WD_STYLE_TYPE) -> bool:
629
+ """Whether ``style_id`` is a character style the uploaded file's runs name
630
+ without the file defining it and no write has given a run, as ``Info``
631
+ reports them (``undefinedRunStyleIds``): python-docx reads such a run's
632
+ style as the default character style, and the export leaves the style
633
+ undefined. After the script gave a run one of them, ``Info`` is read again
634
+ first (it sends the write before it), so the answer is docx-studio's
635
+ record, as every later session reads it."""
636
+ if style_type != WD_STYLE_TYPE.CHARACTER or not style_id:
637
+ return False
638
+ try:
639
+ if session in _runs_restyled:
640
+ _runs_restyled.discard(session)
641
+ forget_style_table(session)
642
+ style_table(session)
643
+ return style_id in _undefined_runs.get(session, frozenset())
644
+ except TypeError:
645
+ return False
646
+
647
+
648
+ def _note_applied_run_style(session: Any, style_id: str | None, style_type: WD_STYLE_TYPE) -> None:
649
+ """Note that the script gives a run ``style_id``, one the uploaded file's
650
+ runs name undefined: docx-studio records the write if it applies, so the
651
+ next read of such a style asks ``Info`` again."""
652
+ if style_type != WD_STYLE_TYPE.CHARACTER or not style_id:
653
+ return
654
+ try:
655
+ if style_id in _undefined_runs.get(session, frozenset()):
656
+ _runs_restyled.add(session)
657
+ except TypeError:
658
+ pass
659
+
660
+
604
661
  def style_id_for(
605
662
  session: Any,
606
663
  style_or_name: object,
@@ -643,7 +700,10 @@ def style_id_for(
643
700
  f"{owner} requires str, {kind} (with ``.style_id``/``.name``), or None; "
644
701
  f"got {type(style_or_name).__name__} {style_or_name!r}",
645
702
  )
646
- return None if style_id == _document_default_style_id(session, style_type) else style_id
703
+ if style_id == _document_default_style_id(session, style_type):
704
+ return None
705
+ _note_applied_run_style(session, style_id, style_type)
706
+ return style_id
647
707
 
648
708
 
649
709
  def _style_id_of_name(session: Any, requested: str, style_type: WD_STYLE_TYPE) -> str:
@@ -347,10 +347,24 @@ def _keep_link_address(run_data: dict, inline: dict) -> None:
347
347
  """Give a picture's run the address of the link it is in where its read
348
348
  sends one apart (``hyperlinkAddress``, for a target that holds a ``#`` of
349
349
  its own), as a text run's read holds it: :attr:`Hyperlink.address` reads
350
- the whole target then, as python-docx does."""
350
+ the whole target then, as python-docx does; that it opens a link of its
351
+ own (``newLink``, :func:`_opens_link`); and that the link has no target
352
+ (``linkWithoutTarget``)."""
351
353
  address: object = inline.get("hyperlinkAddress")
352
354
  if isinstance(address, str):
353
355
  run_data["hyperlinkAddress"] = address
356
+ if inline.get("newLink") is True:
357
+ run_data["newLink"] = True
358
+ if inline.get("linkWithoutTarget") is True:
359
+ run_data["linkWithoutTarget"] = True
360
+
361
+
362
+ def _opens_link(run_data: dict) -> bool:
363
+ """True for the first run of a link that follows another link to the same
364
+ target with nothing between them (``newLink``): two ``w:hyperlink``
365
+ elements side by side, which python-docx reads as two links. Without it,
366
+ runs of one target side by side are one link."""
367
+ return run_data.get("newLink") is True
354
368
 
355
369
 
356
370
  def _picture_run_data(inline: dict, drawing: dict) -> dict:
@@ -372,8 +386,9 @@ def _picture_run_data(inline: dict, drawing: dict) -> dict:
372
386
 
373
387
  def _rendered_page_break_reads(info: object) -> "list[tuple[dict, int]]":
374
388
  """Each rendered page break docx-studio reads in the runs of the paragraph
375
- whose node info is `info` (``renderedPageBreaks``), its links' included, in
376
- order, with its offset in the paragraph's text-address space."""
389
+ whose node info is `info` (``renderedPageBreaks``), its links' and its
390
+ fields' included, in order, with its offset in the paragraph's
391
+ text-address space."""
377
392
  if not isinstance(info, dict):
378
393
  return []
379
394
  node: object = info.get("node")
@@ -382,6 +397,16 @@ def _rendered_page_break_reads(info: object) -> "list[tuple[dict, int]]":
382
397
  reads: list[tuple[dict, int]] = []
383
398
  offset = 0
384
399
  for inline in inlines if isinstance(inlines, list) else []:
400
+ field_run: object = inline.get("fieldRun") if isinstance(inline, dict) else None
401
+ if isinstance(field_run, dict):
402
+ # A run of a field (its begin, code, separate, result or end run):
403
+ # it takes no room in the text-address space, and a break in it
404
+ # stands there.
405
+ field_breaks: object = field_run.get("renderedPageBreaks")
406
+ for brk in field_breaks if isinstance(field_breaks, list) else []:
407
+ if isinstance(brk, dict):
408
+ reads.append((brk, offset))
409
+ continue
385
410
  run: object = inline.get("run") if isinstance(inline, dict) else None
386
411
  if not isinstance(run, dict):
387
412
  # A picture's run: its breaks stand before its drawing, and it holds no text.
@@ -1015,7 +1040,7 @@ class Paragraph:
1015
1040
  if isinstance(drawing, dict):
1016
1041
  # A picture: python-docx's run holding a ``w:drawing``. It
1017
1042
  # takes no room in the text-address space.
1018
- if self._extract_hyperlink_target(inline):
1043
+ if self._extract_hyperlink_target(inline) is not None:
1019
1044
  continue
1020
1045
  run_obj = Run(
1021
1046
  session=self._session,
@@ -1037,7 +1062,7 @@ class Paragraph:
1037
1062
  start: int = offset
1038
1063
  end: int = offset + len(text)
1039
1064
  offset = end
1040
- if self._extract_hyperlink_target(run_data) or _deleted(run_data):
1065
+ if self._extract_hyperlink_target(run_data) is not None or _deleted(run_data):
1041
1066
  continue
1042
1067
  run_obj = Run(
1043
1068
  session=self._session,
@@ -1058,7 +1083,7 @@ class Paragraph:
1058
1083
  start = offset
1059
1084
  end = offset + len(text2)
1060
1085
  offset = end
1061
- if self._extract_hyperlink_target(inline):
1086
+ if self._extract_hyperlink_target(inline) is not None:
1062
1087
  continue
1063
1088
  runs.append(
1064
1089
  Run(
@@ -1248,6 +1273,11 @@ class Paragraph:
1248
1273
  maybe = hl.get("url") or hl.get("target")
1249
1274
  if isinstance(maybe, str) and maybe:
1250
1275
  return maybe
1276
+ # A link with no target (``<w:hyperlink w:history="1">`` holding runs,
1277
+ # with no ``r:id`` and no ``w:anchor``), which python-docx reads as a
1278
+ # link whose address is "" (``linkWithoutTarget``).
1279
+ if run_data.get("linkWithoutTarget") is True:
1280
+ return ""
1251
1281
  return None
1252
1282
 
1253
1283
  @property
@@ -1304,7 +1334,7 @@ class Paragraph:
1304
1334
  # room in the text-address space.
1305
1335
  run_data = _picture_run_data(inline, drawing)
1306
1336
  link = self._extract_hyperlink_target(inline)
1307
- if link:
1337
+ if link is not None:
1308
1338
  run_data["hyperlink"] = link
1309
1339
  _keep_link_address(run_data, inline)
1310
1340
  elif isinstance(maybe_run, dict):
@@ -1373,7 +1403,7 @@ class Paragraph:
1373
1403
 
1374
1404
  # Hyperlinked run. Extend the current span if it shares a
1375
1405
  # target, otherwise close it and start a new one.
1376
- if current is not None and current[0] == target:
1406
+ if current is not None and current[0] == target and not _opens_link(run_data):
1377
1407
  current[1].append((run_data, (start, end)))
1378
1408
  else:
1379
1409
  if current is not None:
@@ -1523,7 +1553,7 @@ class Paragraph:
1523
1553
  # link when it carries one.
1524
1554
  run_data = _picture_run_data(inline, drawing)
1525
1555
  link = self._extract_hyperlink_target(inline)
1526
- if link:
1556
+ if link is not None:
1527
1557
  run_data["hyperlink"] = link
1528
1558
  _keep_link_address(run_data, inline)
1529
1559
  text = ""
@@ -1549,11 +1579,11 @@ class Paragraph:
1549
1579
  offset += len(text)
1550
1580
  continue
1551
1581
  target = self._extract_hyperlink_target(run_data)
1552
- if target:
1582
+ if target is not None:
1553
1583
  start = offset
1554
1584
  offset += len(text)
1555
1585
  segment = (run_data, (start, start + len(text)))
1556
- if current is not None and current[0] == target:
1586
+ if current is not None and current[0] == target and not _opens_link(run_data):
1557
1587
  current[1].append(segment)
1558
1588
  else:
1559
1589
  flushed = _flush_current()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.40.0"
7
+ version = "0.42.0"
8
8
  description = "Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -140,6 +140,9 @@ class FakeDocState:
140
140
  # The paragraph style ids the document's source names without defining
141
141
  # them, as ``Info`` reports them beside the style table (``undefinedStyleIds``).
142
142
  self.undefined_style_ids: list[str] | None = None
143
+ # The character style ids the uploaded file's runs name without defining
144
+ # them, as ``Info`` reports them beside the style table (``undefinedRunStyleIds``).
145
+ self.undefined_run_style_ids: list[str] | None = None
143
146
  # What an older server's ``Info`` lists instead: the paragraph styles in use.
144
147
  self.paragraph_styles_in_use: list[dict] = []
145
148
  # ``docProps/core.xml`` as ``Info`` reports it (``includeCoreProperties``):
@@ -254,6 +257,8 @@ class FakeDocState:
254
257
  info["latentStyles"] = self.latent_styles
255
258
  if "styleTable" in info and self.undefined_style_ids is not None:
256
259
  info["undefinedStyleIds"] = list(self.undefined_style_ids)
260
+ if "styleTable" in info and self.undefined_run_style_ids is not None:
261
+ info["undefinedRunStyleIds"] = list(self.undefined_run_style_ids)
257
262
  if (params or {}).get("includeCoreProperties") and self.core_properties is not None:
258
263
  info["coreProperties"] = dict(self.core_properties)
259
264
  if self.core_properties_default: