athena-python-docx 0.5.0__tar.gz → 0.5.1__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 (256) hide show
  1. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/PKG-INFO +1 -1
  2. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/__init__.py +1 -1
  3. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/pyproject.toml +1 -1
  4. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/scripts/release.sh +8 -8
  5. athena_python_docx-0.5.1/scripts/round_trip_smoke.py +232 -0
  6. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/.gitignore +0 -0
  7. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/CLAUDE.md +0 -0
  8. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/README.md +0 -0
  9. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_batching.py +0 -0
  10. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_buffer.py +0 -0
  11. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_http.py +0 -0
  12. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_http_doc.py +0 -0
  13. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_image_utils.py +0 -0
  14. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/api.py +0 -0
  15. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/client.py +0 -0
  16. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/commands.py +0 -0
  17. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/comments.py +0 -0
  18. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/document.py +0 -0
  19. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/__init__.py +0 -0
  20. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/section.py +0 -0
  21. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/style.py +0 -0
  22. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/table.py +0 -0
  23. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/text.py +0 -0
  24. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/errors.py +0 -0
  25. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/exceptions.py +0 -0
  26. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/opc/__init__.py +0 -0
  27. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/opc/coreprops.py +0 -0
  28. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/section.py +0 -0
  29. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/settings.py +0 -0
  30. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/shape.py +0 -0
  31. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/shared.py +0 -0
  32. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/__init__.py +0 -0
  33. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/style.py +0 -0
  34. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/styles.py +0 -0
  35. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/table.py +0 -0
  36. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/__init__.py +0 -0
  37. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/font.py +0 -0
  38. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/hyperlink.py +0 -0
  39. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/pagebreak.py +0 -0
  40. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/paragraph.py +0 -0
  41. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/parfmt.py +0 -0
  42. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/run.py +0 -0
  43. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/tabstops.py +0 -0
  44. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/typing.py +0 -0
  45. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/scripts/publish.sh +0 -0
  46. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/__init__.py +0 -0
  47. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/conftest.py +0 -0
  48. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/METHODOLOGY.md +0 -0
  49. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/README.md +0 -0
  50. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/__init__.py +0 -0
  51. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ab_probe_cases.py +0 -0
  52. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ab_probe_runner.py +0 -0
  53. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/auto_gen_cases.py +0 -0
  54. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/binary_round_trip.py +0 -0
  55. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/cases.py +0 -0
  56. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/complex_cases.py +0 -0
  57. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/coverage_report.py +0 -0
  58. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/extract.py +0 -0
  59. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/extreme_cases.py +0 -0
  60. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/fake_session.py +0 -0
  61. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/local_runner.py +0 -0
  62. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/mega_cases.py +0 -0
  63. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshot.py +0 -0
  64. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  65. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  66. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  67. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  68. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  69. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  70. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  71. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  72. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  73. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  74. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  75. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  76. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
  77. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  78. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  79. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  80. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  81. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  82. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  83. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  84. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  85. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  86. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  87. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  88. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  89. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  90. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  91. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  92. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  93. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  94. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/23_nested_table.json +0 -0
  95. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  96. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  97. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  98. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  99. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  100. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  101. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  102. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  103. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  104. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  105. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  106. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  107. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  108. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  109. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  110. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  111. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  112. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  113. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  114. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  115. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  116. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  117. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  118. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  119. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  120. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  121. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  122. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -0
  123. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  124. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  125. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  126. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  127. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  128. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  129. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  130. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  131. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  132. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  133. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  134. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  135. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  136. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  137. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  138. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  139. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  140. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  141. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  142. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  143. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  144. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  145. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  146. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  147. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  148. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  149. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  150. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  151. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  152. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  153. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  154. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  155. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  156. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  157. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  158. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  159. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  160. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  161. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  162. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  163. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  164. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  165. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  166. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  167. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  168. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  169. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  170. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  171. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -0
  172. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  173. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  174. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  175. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  176. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  177. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  178. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  179. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  180. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  181. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  182. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  183. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  184. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  185. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  186. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  187. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  188. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  189. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  190. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  191. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  192. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  193. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  194. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  195. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  196. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  197. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  198. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  199. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  200. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  201. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  202. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  203. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  204. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  205. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  206. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  207. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  208. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  209. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  210. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  211. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  212. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  213. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  214. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -0
  215. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  216. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ours_spec.json +0 -0
  217. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/parity_crawl.py +0 -0
  218. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/parity_diff.json +0 -0
  219. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/real_world_cases.py +0 -0
  220. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/round_trip_tests.py +0 -0
  221. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/runner.py +0 -0
  222. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/stock_spec.json +0 -0
  223. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/README.md +0 -0
  224. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/__init__.py +0 -0
  225. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/baseline_gaps.json +0 -0
  226. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/compare.py +0 -0
  227. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/intentional_deviations.json +0 -0
  228. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/introspect.py +0 -0
  229. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  230. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/reports/gap_report.json +0 -0
  231. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/run_parity.py +0 -0
  232. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/snapshots/athena_latest.json +0 -0
  233. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  234. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/test_parity_gap.py +0 -0
  235. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_buffer.py +0 -0
  236. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_command_dataclasses.py +0 -0
  237. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_commands.py +0 -0
  238. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_comments.py +0 -0
  239. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_document_create.py +0 -0
  240. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_http_transport.py +0 -0
  241. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_iter_inner_content.py +0 -0
  242. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_merged_cells.py +0 -0
  243. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_parity_misc.py +0 -0
  244. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_parity_round2.py +0 -0
  245. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_a_behavior.py +0 -0
  246. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_b_headers_footers.py +0 -0
  247. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_c_tables.py +0 -0
  248. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_pr19766_review_fixes.py +0 -0
  249. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_python_docx_api_parity.py +0 -0
  250. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_smoke_integration.py +0 -0
  251. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_acceptance.py +0 -0
  252. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_font.py +0 -0
  253. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_setters_contract.py +0 -0
  254. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_wire_contract.py +0 -0
  255. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_zod_wire_contract.py +0 -0
  256. {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-docx
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx 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.5.0"
9
+ __version__ = "0.5.1"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import flush_all
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.5.0"
7
+ version = "0.5.1"
8
8
  description = "Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # Tag + push a new athena-python-docx release. CI handles the rest:
3
- # PyPI publish, Docker image rebuild, Daytona snapshot creation, Doppler
4
- # flip in agora dev + stg. See
3
+ # PyPI publish, Docker image rebuild, Daytona snapshot creation,
4
+ # Infisical flip in agora dev + staging. See
5
5
  # .github/workflows/athena-python-docx-release.yml for the full flow.
6
6
  #
7
7
  # Usage:
@@ -65,16 +65,16 @@ cat <<EOF
65
65
 
66
66
  Tagged $TAG and pushed. CI is now running the full release pipeline:
67
67
 
68
- 1. PyPI publish → https://pypi.org/project/athena-python-docx/$VERSION/
68
+ 1. PyPI publish → https://pypi.org/project/athena-python-docx/$VERSION/
69
69
  2. Docker image rebuild → athenaintel/daytona-document:$VERSION
70
- 3. Daytona snapshot → document-exec:$VERSION
71
- 4. Doppler flip → agora/dev + agora/stg
70
+ 3. Daytona snapshot → document-exec:$VERSION
71
+ 4. Infisical flip → agora/dev + agora/staging
72
72
 
73
73
  Watch the run:
74
74
  https://github.com/Athena-Intel/demo-app-monorepo/actions/workflows/athena-python-docx-release.yml
75
75
 
76
- For prd rollout, after canary verification:
77
- doppler secrets set --project agora --config prd \\
78
- DAYTONA_DOCUMENT_EXEC_SNAPSHOT=document-exec:$VERSION
76
+ For prod rollout, after canary verification (run from the repo root with
77
+ the Infisical CLI authed against the agora project):
78
+ infisical secrets set DAYTONA_DOCUMENT_EXEC_SNAPSHOT=document-exec:$VERSION --env=prod
79
79
 
80
80
  EOF
@@ -0,0 +1,232 @@
1
+ """Round-trip smoke test against a live docx-studio API + SuperDocument asset.
2
+
3
+ Drives a representative scenario through the SDK (mutations + reads)
4
+ and asserts on the read-back shape. Designed to catch the
5
+ ``SDK → docx-studio → Keryx → SuperDoc`` class of regression that
6
+ unit tests with FakeSession + the cross-language Zod contract test
7
+ can't see — namely, "the wire format we send is technically valid
8
+ but SuperDoc doesn't apply it the way we expect."
9
+
10
+ Per-PR usage in CI (after ``Deploy DOCX Studio Preview`` succeeds):
11
+
12
+ ASSET_ID=asset_ci_round_trip_test \\
13
+ DOCX_STUDIO_BASE_URL=https://docx-studio-pr19782-preview... \\
14
+ ATHENA_DOCX_API_KEY=$CI_DOCX_TEST_API_KEY \\
15
+ python scripts/round_trip_smoke.py
16
+
17
+ Manual usage (against staging, with a personal API key):
18
+
19
+ ASSET_ID=asset_49b963a4-... \\
20
+ ATHENA_DOCX_API_KEY=$BG_STAGING_API_KEY \\
21
+ python scripts/round_trip_smoke.py
22
+
23
+ Exit codes:
24
+ - 0 — all checks passed
25
+ - 1 — at least one check failed (treat as a real regression)
26
+ - 2 — environment / network unavailability (treat as infra flake;
27
+ callers can soft-fail in CI)
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import os
33
+ import sys
34
+ import time
35
+ import traceback
36
+ from dataclasses import dataclass
37
+ from typing import Callable
38
+
39
+
40
+ def _emit(name: str, ok: bool, detail: str = "") -> None:
41
+ glyph = "[ok]" if ok else "[FAIL]"
42
+ line = f"{glyph} {name}"
43
+ if detail:
44
+ line += f" — {detail}"
45
+ print(line, flush=True)
46
+
47
+
48
+ @dataclass
49
+ class CheckResult:
50
+ name: str
51
+ ok: bool
52
+ detail: str = ""
53
+
54
+
55
+ def main() -> int:
56
+ asset_id = os.environ.get("ASSET_ID")
57
+ if not asset_id:
58
+ print(
59
+ "ERROR: set ASSET_ID env var to a SuperDocument asset id the "
60
+ "test API key has write access to. Skipping with exit 2 so "
61
+ "callers can soft-fail in CI.",
62
+ file=sys.stderr,
63
+ )
64
+ return 2
65
+
66
+ base_url = os.environ.get("DOCX_STUDIO_BASE_URL")
67
+ api_key = os.environ.get("ATHENA_DOCX_API_KEY")
68
+ if not api_key:
69
+ print(
70
+ "ERROR: ATHENA_DOCX_API_KEY missing. Skipping with exit 2.",
71
+ file=sys.stderr,
72
+ )
73
+ return 2
74
+
75
+ # Insert local SDK first so this script always exercises the
76
+ # just-built code (when run from the repo) rather than whatever
77
+ # version is on the PYTHONPATH.
78
+ sdk_root = os.path.join(
79
+ os.path.dirname(os.path.abspath(__file__)),
80
+ "..",
81
+ )
82
+ sys.path.insert(0, os.path.abspath(sdk_root))
83
+
84
+ try:
85
+ from docx import Document
86
+ from docx.errors import DocxError
87
+ except ImportError as e:
88
+ print(f"ERROR: failed to import SDK from {sdk_root}: {e}", file=sys.stderr)
89
+ return 2
90
+
91
+ print(f"[setup] base_url={base_url or '<default>'}")
92
+ print(f"[setup] asset_id={asset_id}")
93
+ print(f"[setup] sdk_root={sdk_root}")
94
+
95
+ # Tag every paragraph with a unique suffix so re-runs against a
96
+ # long-lived asset stay debuggable (we can grep the asset for the
97
+ # token and find the run that wrote it).
98
+ run_token = f"ci-{int(time.time())}"
99
+
100
+ try:
101
+ kwargs: dict = {"api_key": api_key}
102
+ if base_url:
103
+ kwargs["base_url"] = base_url
104
+ doc = Document(asset_id, **kwargs)
105
+ except DocxError as e:
106
+ print(f"ERROR: failed to open document: {e}", file=sys.stderr)
107
+ # Network / auth / 502 — caller treats as infra flake.
108
+ return 2
109
+
110
+ results: list[CheckResult] = []
111
+
112
+ def run_check(name: str, fn: Callable[[], None]) -> None:
113
+ try:
114
+ fn()
115
+ results.append(CheckResult(name, True))
116
+ _emit(name, True)
117
+ except AssertionError as e:
118
+ results.append(CheckResult(name, False, str(e)))
119
+ _emit(name, False, str(e))
120
+ except Exception as e: # noqa: BLE001
121
+ results.append(CheckResult(name, False, f"{type(e).__name__}: {e}"))
122
+ _emit(name, False, f"{type(e).__name__}: {e}")
123
+ traceback.print_exc()
124
+
125
+ # -----------------------------------------------------------------
126
+ # Check 1 (Round 3 #2): Document.add_paragraph segments tabs/newlines
127
+ # -----------------------------------------------------------------
128
+ expected_text_1 = f"[{run_token}] hello\tworld\nfoo"
129
+
130
+ def check_paragraph_segments_tabs_and_newlines() -> None:
131
+ p = doc.add_paragraph(expected_text_1)
132
+ # Read-back: paragraph.text must include the tab and newline as
133
+ # \t and \n (Round 2 #1: _extract_text now renders these).
134
+ # Drain any pending writes to make sure SuperDoc has applied
135
+ # them before we read.
136
+ doc.save()
137
+ text_back = p.text
138
+ assert text_back == expected_text_1, (
139
+ f"add_paragraph + paragraph.text round-trip diverged: "
140
+ f"sent {expected_text_1!r}, got {text_back!r}"
141
+ )
142
+
143
+ run_check(
144
+ "round-3 #2: Document.add_paragraph segments \\t / \\n into inlines",
145
+ check_paragraph_segments_tabs_and_newlines,
146
+ )
147
+
148
+ # -----------------------------------------------------------------
149
+ # Check 2 (Round 3 #3): Document.add_heading segments tabs/newlines
150
+ # -----------------------------------------------------------------
151
+ expected_heading = f"[{run_token}] heading\twith-tab"
152
+
153
+ def check_heading_segments_tab() -> None:
154
+ h = doc.add_heading(expected_heading, level=2)
155
+ doc.save()
156
+ text_back = h.text
157
+ assert text_back == expected_heading, (
158
+ f"add_heading + paragraph.text round-trip diverged: "
159
+ f"sent {expected_heading!r}, got {text_back!r}"
160
+ )
161
+
162
+ run_check(
163
+ "round-3 #3: Document.add_heading segments \\t into inline",
164
+ check_heading_segments_tab,
165
+ )
166
+
167
+ # -----------------------------------------------------------------
168
+ # Check 3 (Round 1 + Round 2 #1): bold=True applies, paragraph.text
169
+ # ignores the mark, runs[0].text holds the segment
170
+ # -----------------------------------------------------------------
171
+ expected_bold = f"[{run_token}] this is bold"
172
+
173
+ def check_bold_round_trip() -> None:
174
+ p = doc.add_paragraph(expected_bold)
175
+ doc.save()
176
+ runs = list(p.runs)
177
+ assert runs, "add_paragraph produced no runs"
178
+ runs[0].bold = True
179
+ doc.save()
180
+ # Re-fetch and verify bold mark stuck. Live read goes through
181
+ # _read_inline_attr which re-fetches the paragraph node.
182
+ runs2 = list(p.runs)
183
+ assert runs2 and runs2[0].bold is True, (
184
+ f"bold=True did not persist; got runs[0].bold={runs2 and runs2[0].bold}"
185
+ )
186
+
187
+ run_check(
188
+ "round-1: Run.bold=True persists via FormatApply",
189
+ check_bold_round_trip,
190
+ )
191
+
192
+ # -----------------------------------------------------------------
193
+ # Check 4 (Round 2 #1): paragraph.text reads tabs/newlines verbatim
194
+ # — covered by checks 1 + 2 already, but pin the expected sequence
195
+ # -----------------------------------------------------------------
196
+ def check_paragraph_text_renders_control_chars() -> None:
197
+ # Use a dedicated paragraph so we don't depend on read order.
198
+ sentinel = f"[{run_token}] tab=\there\nbreak=line"
199
+ p = doc.add_paragraph(sentinel)
200
+ doc.save()
201
+ assert p.text == sentinel, (
202
+ f"paragraph.text dropped control chars: {p.text!r} vs {sentinel!r}"
203
+ )
204
+
205
+ run_check(
206
+ "round-2 #1: paragraph.text renders \\t and \\n verbatim",
207
+ check_paragraph_text_renders_control_chars,
208
+ )
209
+
210
+ # -----------------------------------------------------------------
211
+ # Summary
212
+ # -----------------------------------------------------------------
213
+ failed = [r for r in results if not r.ok]
214
+ print()
215
+ print(f"=== Summary: {len(results) - len(failed)}/{len(results)} passed ===")
216
+ for r in failed:
217
+ print(f" [FAIL] {r.name} — {r.detail}")
218
+ if failed:
219
+ return 1
220
+ print("All round-trip checks passed.")
221
+ return 0
222
+
223
+
224
+ if __name__ == "__main__":
225
+ try:
226
+ rc = main()
227
+ except KeyboardInterrupt:
228
+ rc = 130
229
+ except Exception:
230
+ traceback.print_exc()
231
+ rc = 1
232
+ raise SystemExit(rc)