athena-python-docx 0.5.3__tar.gz → 0.6.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 (280) hide show
  1. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/PKG-INFO +1 -1
  2. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/__init__.py +1 -1
  3. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/enum/text.py +46 -2
  4. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/parfmt.py +89 -5
  5. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/tabstops.py +61 -20
  6. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/pyproject.toml +1 -1
  7. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/reports/GAP_ANALYSIS.md +27 -2
  8. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/reports/gap_report.json +1650 -0
  9. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/snapshots/athena_latest.json +1037 -133
  10. athena_python_docx-0.6.0/tests/test_silent_stub_parfmt.py +367 -0
  11. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/.gitignore +0 -0
  12. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/CLAUDE.md +0 -0
  13. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/README.md +0 -0
  14. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_batching.py +0 -0
  15. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_buffer.py +0 -0
  16. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_http.py +0 -0
  17. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_http_doc.py +0 -0
  18. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_image_utils.py +0 -0
  19. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/_ptc.py +0 -0
  20. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/api.py +0 -0
  21. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/client.py +0 -0
  22. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/commands.py +0 -0
  23. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/comments.py +0 -0
  24. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/document.py +0 -0
  25. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/enum/__init__.py +0 -0
  26. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/enum/section.py +0 -0
  27. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/enum/style.py +0 -0
  28. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/enum/table.py +0 -0
  29. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/errors.py +0 -0
  30. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/exceptions.py +0 -0
  31. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/opc/__init__.py +0 -0
  32. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/opc/coreprops.py +0 -0
  33. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/revisions.py +0 -0
  34. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/section.py +0 -0
  35. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/settings.py +0 -0
  36. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/shape.py +0 -0
  37. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/shared.py +0 -0
  38. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/styles/__init__.py +0 -0
  39. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/styles/style.py +0 -0
  40. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/styles/styles.py +0 -0
  41. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/table.py +0 -0
  42. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/__init__.py +0 -0
  43. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/font.py +0 -0
  44. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/hyperlink.py +0 -0
  45. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/pagebreak.py +0 -0
  46. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/paragraph.py +0 -0
  47. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/text/run.py +0 -0
  48. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/docx/typing.py +0 -0
  49. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/scripts/publish.sh +0 -0
  50. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/scripts/release.sh +0 -0
  51. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/scripts/round_trip_smoke.py +0 -0
  52. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/__init__.py +0 -0
  53. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/conftest.py +0 -0
  54. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/METHODOLOGY.md +0 -0
  55. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/README.md +0 -0
  56. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/__init__.py +0 -0
  57. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/ab_probe_cases.py +0 -0
  58. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/ab_probe_runner.py +0 -0
  59. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/auto_gen_cases.py +0 -0
  60. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/binary_round_trip.py +0 -0
  61. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/cases.py +0 -0
  62. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/complex_cases.py +0 -0
  63. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/coverage_report.py +0 -0
  64. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/extract.py +0 -0
  65. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/extreme_cases.py +0 -0
  66. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/fake_session.py +0 -0
  67. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/local_runner.py +0 -0
  68. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/mega_cases.py +0 -0
  69. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshot.py +0 -0
  70. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  71. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  72. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  73. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  74. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  75. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  76. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  77. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  78. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  79. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  80. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  81. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  82. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
  83. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  84. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  85. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  86. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  87. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  88. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  89. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  90. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  91. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  92. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  93. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  94. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  95. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  96. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  97. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  98. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  99. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  100. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/23_nested_table.json +0 -0
  101. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  102. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  103. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  104. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  105. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  106. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  107. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  108. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  109. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  110. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  111. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  112. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  113. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  114. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  115. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  116. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  117. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  118. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  119. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  120. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  121. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  122. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  123. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  124. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  125. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  126. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  127. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  128. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -0
  129. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  130. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  131. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  132. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  133. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  134. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  135. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  136. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  137. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  138. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  139. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  140. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  141. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  142. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  143. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  144. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  145. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  146. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  147. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  148. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  149. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  150. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  151. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  152. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  153. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  154. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  155. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  156. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  157. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  158. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  159. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  160. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  161. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  162. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  163. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  164. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  165. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  166. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  167. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  168. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  169. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  170. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  171. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  172. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  173. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  174. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  175. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  176. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  177. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -0
  178. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  179. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  180. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  181. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  182. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  183. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  184. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  185. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  186. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  187. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  188. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  189. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  190. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  191. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  192. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  193. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  194. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  195. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  196. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  197. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  198. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  199. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  200. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  201. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  202. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  203. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  204. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  205. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  206. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  207. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  208. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  209. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  210. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  211. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  212. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  213. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  214. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  215. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  216. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  217. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  218. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  219. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  220. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -0
  221. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  222. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/ours_spec.json +0 -0
  223. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/parity_crawl.py +0 -0
  224. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/parity_diff.json +0 -0
  225. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/real_world_cases.py +0 -0
  226. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/round_trip_tests.py +0 -0
  227. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/runner.py +0 -0
  228. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/fidelity/stock_spec.json +0 -0
  229. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/README.md +0 -0
  230. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/__init__.py +0 -0
  231. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/baseline_gaps.json +0 -0
  232. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/compare.py +0 -0
  233. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/intentional_deviations.json +0 -0
  234. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/introspect.py +0 -0
  235. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/run_parity.py +0 -0
  236. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  237. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/parity/test_parity_gap.py +0 -0
  238. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_batching_perf.py +0 -0
  239. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_buffer.py +0 -0
  240. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_command_dataclasses.py +0 -0
  241. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_commands.py +0 -0
  242. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_comments.py +0 -0
  243. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_document_create.py +0 -0
  244. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_http_transport.py +0 -0
  245. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_iter_inner_content.py +0 -0
  246. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_merged_cells.py +0 -0
  247. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_parity_misc.py +0 -0
  248. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_parity_round2.py +0 -0
  249. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_phase_a_behavior.py +0 -0
  250. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_phase_b_headers_footers.py +0 -0
  251. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_phase_c_tables.py +0 -0
  252. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_pr19766_review_fixes.py +0 -0
  253. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_ptc.py +0 -0
  254. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_python_docx_api_parity.py +0 -0
  255. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_revisions.py +0 -0
  256. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_add_picture.py +0 -0
  257. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_comments_get.py +0 -0
  258. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_document_audit.py +0 -0
  259. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_document_element.py +0 -0
  260. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_font_audit.py +0 -0
  261. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_header_footer.py +0 -0
  262. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_hyperlink.py +0 -0
  263. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_misc.py +0 -0
  264. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  265. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  266. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_section_audit.py +0 -0
  267. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_settings.py +0 -0
  268. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_shared_audit.py +0 -0
  269. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_style.py +0 -0
  270. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_styles.py +0 -0
  271. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_table_audit.py +0 -0
  272. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_table_cell.py +0 -0
  273. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  274. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_smoke_integration.py +0 -0
  275. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_style_acceptance.py +0 -0
  276. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_style_font.py +0 -0
  277. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_style_setters_contract.py +0 -0
  278. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_wire_contract.py +0 -0
  279. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/tests/test_zod_wire_contract.py +0 -0
  280. {athena_python_docx-0.5.3 → athena_python_docx-0.6.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-docx
3
- Version: 0.5.3
3
+ Version: 0.6.0
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.3"
9
+ __version__ = "0.6.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import flush_all
@@ -2,14 +2,49 @@
2
2
 
3
3
  Values map to Superdoc primitives where supported; unmapped values
4
4
  (e.g. Thai/Arabic justification variants) still parse but serialize to
5
- their best Superdoc equivalent.
5
+ their best Superdoc equivalent and emit
6
+ :class:`PendingEnumCoercionWarning` so the caller knows the wire-level
7
+ intent was downgraded.
6
8
  """
7
9
 
8
10
  from __future__ import annotations
9
11
 
12
+ import warnings
10
13
  from enum import Enum
11
14
 
12
15
 
16
+ class PendingEnumCoercionWarning(UserWarning):
17
+ """Emitted when an enum member's :meth:`to_superdoc` collapses the
18
+ value to a different SuperDoc-supported primitive.
19
+
20
+ Examples:
21
+ - ``WD_ALIGN_PARAGRAPH.THAI_JUSTIFY.to_superdoc()`` returns
22
+ ``"justify"`` because SuperDoc 1.8's ``set_alignment`` rejects
23
+ ``thaiJustify``.
24
+ - ``WD_TAB_ALIGNMENT.CLEAR.to_superdoc()`` returns ``"left"``
25
+ because SuperDoc has no equivalent clear/end/num/start tab
26
+ vocabulary.
27
+
28
+ Tracked in ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``. Pin so a
29
+ future SuperDoc that lands the full vocabulary can flip the
30
+ coercion off and these warnings disappear.
31
+ """
32
+
33
+
34
+ def _warn_enum_coercion(enum_member: object, fallback: str) -> None:
35
+ """Emit a single warning identifying which enum member got
36
+ coerced to which SuperDoc primitive."""
37
+ warnings.warn(
38
+ f"{enum_member!r}.to_superdoc() returns {fallback!r} — "
39
+ f"SuperDoc 1.8 doesn't surface this value, so the wire ships "
40
+ f"the closest supported primitive. The visual result may "
41
+ f"differ from python-docx. Tracked in "
42
+ f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
43
+ PendingEnumCoercionWarning,
44
+ stacklevel=3,
45
+ )
46
+
47
+
13
48
  class WD_ALIGN_PARAGRAPH(Enum):
14
49
  """Paragraph alignment (justification)."""
15
50
 
@@ -26,7 +61,10 @@ class WD_ALIGN_PARAGRAPH(Enum):
26
61
  def to_superdoc(self) -> str:
27
62
  # Superdoc only supports left/center/right/justify; coerce the
28
63
  # distributed/thai variants to "justify" so set_alignment doesn't
29
- # reject them.
64
+ # reject them. Emit PendingEnumCoercionWarning so the caller
65
+ # learns the wire-level intent was downgraded (silently shipping
66
+ # "justify" when the user asked for thaiJustify is the silent
67
+ # stub the parity loop is hunting).
30
68
  if self in (
31
69
  WD_ALIGN_PARAGRAPH.DISTRIBUTE,
32
70
  WD_ALIGN_PARAGRAPH.JUSTIFY_MED,
@@ -34,6 +72,7 @@ class WD_ALIGN_PARAGRAPH(Enum):
34
72
  WD_ALIGN_PARAGRAPH.JUSTIFY_LOW,
35
73
  WD_ALIGN_PARAGRAPH.THAI_JUSTIFY,
36
74
  ):
75
+ _warn_enum_coercion(self, "justify")
37
76
  return "justify"
38
77
  return self.value
39
78
 
@@ -82,6 +121,10 @@ class WD_TAB_ALIGNMENT(Enum):
82
121
  START = "start"
83
122
 
84
123
  def to_superdoc(self) -> str:
124
+ # Superdoc only supports left/center/right/decimal/bar for tab
125
+ # alignment. ``LIST`` / ``CLEAR`` / ``END`` / ``NUM`` / ``START``
126
+ # are upstream-only — emit PendingEnumCoercionWarning so callers
127
+ # learn the wire-level intent was downgraded to ``"left"``.
85
128
  if self in (
86
129
  WD_TAB_ALIGNMENT.LIST,
87
130
  WD_TAB_ALIGNMENT.CLEAR,
@@ -89,6 +132,7 @@ class WD_TAB_ALIGNMENT(Enum):
89
132
  WD_TAB_ALIGNMENT.NUM,
90
133
  WD_TAB_ALIGNMENT.START,
91
134
  ):
135
+ _warn_enum_coercion(self, "left")
92
136
  return "left"
93
137
  return self.value
94
138
 
@@ -11,6 +11,7 @@ Setters accept:
11
11
 
12
12
  from __future__ import annotations
13
13
 
14
+ import warnings
14
15
  from typing import TYPE_CHECKING
15
16
 
16
17
  from docx._batching import run_sync
@@ -22,6 +23,49 @@ if TYPE_CHECKING:
22
23
  from docx.text.tabstops import TabStops
23
24
 
24
25
 
26
+ class PendingParfmtClearWarning(UserWarning):
27
+ """Emitted when a ``ParagraphFormat`` setter is asked to clear a
28
+ trivalent (None/True/False) property whose SuperDoc wire op
29
+ doesn't expose a clear primitive.
30
+
31
+ Behavior pinned for parity with python-docx 1.x semantics
32
+ (``None`` means "inherit from style") even though SuperDoc 1.8 can
33
+ only set explicit values. The setter is a no-op at the wire level
34
+ but emits this warning so silent inheritance-vs-set divergence
35
+ surfaces during agent runs. Tracked in
36
+ ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``.
37
+ """
38
+
39
+
40
+ def _warn_parfmt_clear(prop: str) -> None:
41
+ warnings.warn(
42
+ f"ParagraphFormat.{prop} = None was IGNORED — SuperDoc 1.8 "
43
+ f"has no clear-op for this trivalent attribute. The value "
44
+ f"stays whatever it was last set to (or inherited from the "
45
+ f"paragraph style). Tracked in "
46
+ f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
47
+ PendingParfmtClearWarning,
48
+ stacklevel=3,
49
+ )
50
+
51
+
52
+ def _require_bool(prop: str, value: object) -> bool:
53
+ """Reject non-bool input for trivalent on/off properties.
54
+
55
+ ``bool`` is a Python ``int`` subclass, so a bare ``True``/``False``
56
+ would otherwise hit any ``isinstance(value, int)`` branch first
57
+ and produce surprising semantics (e.g. ``line_spacing = True``
58
+ setting a 1× multiplier). Callers must pass real bools.
59
+ """
60
+ if not isinstance(value, bool):
61
+ raise TypeError(
62
+ f"ParagraphFormat.{prop} requires bool (True/False/None); "
63
+ f"got {type(value).__name__} {value!r}. python-docx 1.x "
64
+ f"rejects truthy non-bool input here too.",
65
+ )
66
+ return value
67
+
68
+
25
69
  def _to_twips(value: object) -> int:
26
70
  """Coerce a length-ish input to twips (int)."""
27
71
  if value is None:
@@ -223,6 +267,16 @@ class ParagraphFormat:
223
267
  if value is None:
224
268
  self._clear_spacing()
225
269
  return
270
+ # ``bool`` is a subclass of ``int`` in Python, so ``True``/``False``
271
+ # would otherwise silently hit the ``1 <= value <= 4`` branch
272
+ # (1× multiplier) or the EMU fallthrough (0). Reject upfront —
273
+ # python-docx 1.x raises ``TypeError`` for non-Length/numeric.
274
+ if isinstance(value, bool):
275
+ raise TypeError(
276
+ f"line_spacing requires float/int/Length, not bool; "
277
+ f"got {value!r}. Pass 1.0 / 1.5 / 2.0 for "
278
+ f"single/1.5×/double, or a Length for exact spacing.",
279
+ )
226
280
  if isinstance(value, Length):
227
281
  self._set_spacing(line=value.twips, lineRule="exact")
228
282
  return
@@ -268,7 +322,13 @@ class ParagraphFormat:
268
322
  from docx.enum.text import WD_LINE_SPACING
269
323
 
270
324
  if value is None:
325
+ self._clear_spacing()
271
326
  return
327
+ if not isinstance(value, WD_LINE_SPACING):
328
+ raise ValueError(
329
+ f"line_spacing_rule: expected WD_LINE_SPACING, got "
330
+ f"{type(value).__name__} {value!r}",
331
+ )
272
332
  if value == WD_LINE_SPACING.SINGLE:
273
333
  self._set_spacing(line=240, lineRule="auto")
274
334
  elif value == WD_LINE_SPACING.ONE_POINT_FIVE:
@@ -279,6 +339,22 @@ class ParagraphFormat:
279
339
  self._set_spacing(line=240, lineRule="exact")
280
340
  elif value == WD_LINE_SPACING.AT_LEAST:
281
341
  self._set_spacing(line=240, lineRule="atLeast")
342
+ elif value == WD_LINE_SPACING.MULTIPLE:
343
+ # MULTIPLE without an explicit numeric value is meaningless;
344
+ # python-docx 1.x raises ``ValueError`` for the same reason.
345
+ raise ValueError(
346
+ "line_spacing_rule = WD_LINE_SPACING.MULTIPLE is not "
347
+ "settable on its own — set line_spacing to a float "
348
+ "multiplier (e.g. 1.5) instead, which implicitly uses "
349
+ "the MULTIPLE rule via lineRule='auto'.",
350
+ )
351
+ else:
352
+ # Defensive: any new enum member we haven't mapped to a wire
353
+ # primitive should surface as ValueError, not silently no-op.
354
+ raise ValueError(
355
+ f"line_spacing_rule: unsupported WD_LINE_SPACING "
356
+ f"member {value!r} — no wire mapping in athena-python-docx.",
357
+ )
282
358
 
283
359
  # ---- keep / widow ----
284
360
  @property
@@ -290,8 +366,9 @@ class ParagraphFormat:
290
366
  @keep_together.setter
291
367
  def keep_together(self, value: bool | None) -> None:
292
368
  if value is None:
369
+ _warn_parfmt_clear("keep_together")
293
370
  return
294
- self._set_keep(keepLines=bool(value))
371
+ self._set_keep(keepLines=_require_bool("keep_together", value))
295
372
 
296
373
  @property
297
374
  def keep_with_next(self) -> bool | None:
@@ -302,8 +379,9 @@ class ParagraphFormat:
302
379
  @keep_with_next.setter
303
380
  def keep_with_next(self, value: bool | None) -> None:
304
381
  if value is None:
382
+ _warn_parfmt_clear("keep_with_next")
305
383
  return
306
- self._set_keep(keepNext=bool(value))
384
+ self._set_keep(keepNext=_require_bool("keep_with_next", value))
307
385
 
308
386
  @property
309
387
  def widow_control(self) -> bool | None:
@@ -314,8 +392,9 @@ class ParagraphFormat:
314
392
  @widow_control.setter
315
393
  def widow_control(self, value: bool | None) -> None:
316
394
  if value is None:
395
+ _warn_parfmt_clear("widow_control")
317
396
  return
318
- self._set_keep(widowControl=bool(value))
397
+ self._set_keep(widowControl=_require_bool("widow_control", value))
319
398
 
320
399
  @property
321
400
  def page_break_before(self) -> bool | None:
@@ -326,11 +405,16 @@ class ParagraphFormat:
326
405
  @page_break_before.setter
327
406
  def page_break_before(self, value: bool | None) -> None:
328
407
  if value is None:
408
+ _warn_parfmt_clear("page_break_before")
329
409
  return
330
- # Superdoc's setFlowOptions handles pageBreakBefore
410
+ # Superdoc's setFlowOptions handles pageBreakBefore.
411
+ # Reject non-bool to keep parity with python-docx 1.x's strict
412
+ # ``_OnOff`` handling — ``bool(non_bool_value)`` silently coerces
413
+ # garbage to True.
414
+ coerced: bool = _require_bool("page_break_before", value)
331
415
  run_sync(
332
416
  self._paragraph._session.doc.format.paragraph.set_flow_options(
333
- {"target": self._target(), "pageBreakBefore": bool(value)},
417
+ {"target": self._target(), "pageBreakBefore": coerced},
334
418
  ),
335
419
  )
336
420
 
@@ -23,6 +23,59 @@ if TYPE_CHECKING:
23
23
  from docx.text.parfmt import ParagraphFormat
24
24
 
25
25
 
26
+ def _coerce_alignment(value: object) -> str:
27
+ """Coerce ``WD_TAB_ALIGNMENT`` or its string form to the SuperDoc
28
+ wire value, rejecting anything else.
29
+
30
+ Previously the setter / factory accepted ``str(value)`` for any
31
+ input, shipping bogus alignment strings to the wire (SuperDoc
32
+ silently fell back to ``left``). python-docx 1.x validates against
33
+ the enum at the XML serialization layer.
34
+ """
35
+ if isinstance(value, WD_TAB_ALIGNMENT):
36
+ return value.to_superdoc()
37
+ if isinstance(value, str):
38
+ try:
39
+ return WD_TAB_ALIGNMENT(value).to_superdoc()
40
+ except ValueError as e:
41
+ raise ValueError(
42
+ f"Tab stop alignment {value!r} is not a valid "
43
+ f"WD_TAB_ALIGNMENT value. Expected one of "
44
+ f"{[m.value for m in WD_TAB_ALIGNMENT]} or a "
45
+ f"WD_TAB_ALIGNMENT enum member.",
46
+ ) from e
47
+ raise TypeError(
48
+ f"Tab stop alignment must be WD_TAB_ALIGNMENT or str; "
49
+ f"got {type(value).__name__} {value!r}",
50
+ )
51
+
52
+
53
+ def _coerce_leader(value: object) -> str:
54
+ """Coerce ``WD_TAB_LEADER`` or its string form to the SuperDoc
55
+ wire value, rejecting anything else.
56
+
57
+ Same rationale as :func:`_coerce_alignment` — the prior
58
+ ``str(value)`` accept-anything path silently shipped bogus leader
59
+ values that SuperDoc swallowed.
60
+ """
61
+ if isinstance(value, WD_TAB_LEADER):
62
+ return value.to_superdoc()
63
+ if isinstance(value, str):
64
+ try:
65
+ return WD_TAB_LEADER(value).to_superdoc()
66
+ except ValueError as e:
67
+ raise ValueError(
68
+ f"Tab stop leader {value!r} is not a valid "
69
+ f"WD_TAB_LEADER value. Expected one of "
70
+ f"{[m.value for m in WD_TAB_LEADER]} or a "
71
+ f"WD_TAB_LEADER enum member.",
72
+ ) from e
73
+ raise TypeError(
74
+ f"Tab stop leader must be WD_TAB_LEADER or str; "
75
+ f"got {type(value).__name__} {value!r}",
76
+ )
77
+
78
+
26
79
  class TabStop:
27
80
  """A single tab stop entry. Returned by :class:`TabStops` iteration
28
81
  and by :meth:`TabStops.add_tab_stop`.
@@ -63,12 +116,7 @@ class TabStop:
63
116
 
64
117
  @alignment.setter
65
118
  def alignment(self, value: "WD_TAB_ALIGNMENT | str") -> None:
66
- from docx.enum.text import WD_TAB_ALIGNMENT
67
-
68
- if isinstance(value, WD_TAB_ALIGNMENT):
69
- self._data["alignment"] = value.to_superdoc()
70
- else:
71
- self._data["alignment"] = str(value)
119
+ self._data["alignment"] = _coerce_alignment(value)
72
120
  self._parent._rewrite_from_data([s._data for s in self._parent._stops()])
73
121
 
74
122
  @property
@@ -83,12 +131,7 @@ class TabStop:
83
131
 
84
132
  @leader.setter
85
133
  def leader(self, value: "WD_TAB_LEADER | str") -> None:
86
- from docx.enum.text import WD_TAB_LEADER
87
-
88
- if isinstance(value, WD_TAB_LEADER):
89
- self._data["leader"] = value.to_superdoc()
90
- else:
91
- self._data["leader"] = str(value)
134
+ self._data["leader"] = _coerce_leader(value)
92
135
  self._parent._rewrite_from_data([s._data for s in self._parent._stops()])
93
136
 
94
137
 
@@ -170,15 +213,13 @@ class TabStops:
170
213
 
171
214
  ``alignment`` defaults to ``WD_TAB_ALIGNMENT.LEFT``, ``leader``
172
215
  defaults to ``WD_TAB_LEADER.SPACES`` — matching python-docx.
216
+ Bogus enum-equivalent strings now raise ``ValueError``; a
217
+ non-enum/non-str input raises ``TypeError``. Previously any
218
+ ``str(value)`` was shipped to the wire and SuperDoc silently
219
+ fell back to defaults.
173
220
  """
174
- align_val: str = (
175
- alignment.to_superdoc()
176
- if isinstance(alignment, WD_TAB_ALIGNMENT)
177
- else str(alignment)
178
- )
179
- leader_val: str = (
180
- leader.to_superdoc() if isinstance(leader, WD_TAB_LEADER) else str(leader)
181
- )
221
+ align_val: str = _coerce_alignment(alignment)
222
+ leader_val: str = _coerce_leader(leader)
182
223
  pos_twips: int = _to_twips(position)
183
224
  run_sync(
184
225
  self._parfmt._paragraph._session.doc.format.paragraph.set_tab_stop(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.5.3"
7
+ version = "0.6.0"
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"
@@ -10,10 +10,10 @@ Comparing **athena-python-docx 0.5.2** (39 modules) against **python-docx 1.2.0*
10
10
  | `class_missing` | 201 | 0 | 201 |
11
11
  | `member_missing` | 71 | 0 | 71 |
12
12
  | `member_kind_drift` | 0 | 0 | 0 |
13
- | `ctor_signature_drift` | 32 | 0 | 32 |
13
+ | `ctor_signature_drift` | 57 | 0 | 57 |
14
14
  | `signature_drift` | 1 | 0 | 1 |
15
15
  | `return_annotation_drift` | 0 | 0 | 0 |
16
- | **TOTAL** | **372** | **0** | **372** |
16
+ | **TOTAL** | **397** | **0** | **397** |
17
17
 
18
18
  ## Intentional deviations (filtered out)
19
19
 
@@ -22,6 +22,31 @@ These are documented as intentional in `tests/parity/intentional_deviations.json
22
22
  - `docx.comments.Comment` (ctor_signature_drift)
23
23
  - `docx.comments.Comments` (ctor_signature_drift)
24
24
  - `docx.document.Document` (ctor_signature_drift)
25
+ - `docx.enum.section.WD_HEADER_FOOTER` (ctor_signature_drift)
26
+ - `docx.enum.section.WD_HEADER_FOOTER_INDEX` (ctor_signature_drift)
27
+ - `docx.enum.section.WD_ORIENT` (ctor_signature_drift)
28
+ - `docx.enum.section.WD_ORIENTATION` (ctor_signature_drift)
29
+ - `docx.enum.section.WD_SECTION` (ctor_signature_drift)
30
+ - `docx.enum.section.WD_SECTION_START` (ctor_signature_drift)
31
+ - `docx.enum.style.WD_BUILTIN_STYLE` (ctor_signature_drift)
32
+ - `docx.enum.style.WD_STYLE` (ctor_signature_drift)
33
+ - `docx.enum.style.WD_STYLE_TYPE` (ctor_signature_drift)
34
+ - `docx.enum.table.WD_ALIGN_VERTICAL` (ctor_signature_drift)
35
+ - `docx.enum.table.WD_CELL_VERTICAL_ALIGNMENT` (ctor_signature_drift)
36
+ - `docx.enum.table.WD_ROW_HEIGHT` (ctor_signature_drift)
37
+ - `docx.enum.table.WD_ROW_HEIGHT_RULE` (ctor_signature_drift)
38
+ - `docx.enum.table.WD_TABLE_ALIGNMENT` (ctor_signature_drift)
39
+ - `docx.enum.table.WD_TABLE_DIRECTION` (ctor_signature_drift)
40
+ - `docx.enum.text.WD_ALIGN_PARAGRAPH` (ctor_signature_drift)
41
+ - `docx.enum.text.WD_BREAK` (ctor_signature_drift)
42
+ - `docx.enum.text.WD_BREAK_TYPE` (ctor_signature_drift)
43
+ - `docx.enum.text.WD_COLOR` (ctor_signature_drift)
44
+ - `docx.enum.text.WD_COLOR_INDEX` (ctor_signature_drift)
45
+ - `docx.enum.text.WD_LINE_SPACING` (ctor_signature_drift)
46
+ - `docx.enum.text.WD_PARAGRAPH_ALIGNMENT` (ctor_signature_drift)
47
+ - `docx.enum.text.WD_TAB_ALIGNMENT` (ctor_signature_drift)
48
+ - `docx.enum.text.WD_TAB_LEADER` (ctor_signature_drift)
49
+ - `docx.enum.text.WD_UNDERLINE` (ctor_signature_drift)
25
50
  - `docx.opc.coreprops.CoreProperties` (ctor_signature_drift)
26
51
  - `docx.section.Section` (ctor_signature_drift)
27
52
  - `docx.section.Sections` (ctor_signature_drift)