athena-python-docx 0.5.3__tar.gz → 0.6.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 (302) hide show
  1. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/PKG-INFO +1 -1
  2. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/__init__.py +1 -1
  3. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/comments.py +20 -0
  4. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/document.py +31 -6
  5. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/section.py +18 -0
  6. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/text.py +73 -2
  7. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/section.py +87 -20
  8. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/shape.py +26 -0
  9. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/table.py +118 -19
  10. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/paragraph.py +163 -8
  11. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/parfmt.py +89 -5
  12. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/run.py +172 -8
  13. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/tabstops.py +61 -20
  14. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/pyproject.toml +1 -1
  15. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/03_runs_with_formatting.json +4 -4
  16. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -1
  17. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -1
  18. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -1
  19. athena_python_docx-0.6.1/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +7 -0
  20. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -1
  21. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -1
  22. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -1
  23. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -1
  24. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -1
  25. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/35_full_report.json +0 -4
  26. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -1
  27. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/07_font_subscript_superscript.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +3 -3
  28. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -1
  29. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -1
  30. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -1
  31. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -1
  32. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -7
  33. athena_python_docx-0.6.1/tests/fidelity/op_snapshots/54_empty_everything.json +4 -0
  34. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/03_runs_with_formatting.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/55_single_character_runs.json +2 -5
  35. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -6
  36. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -3
  37. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/55_single_character_runs.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +3 -6
  38. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/68_invoice.json +0 -1
  39. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/69_newsletter.json +0 -9
  40. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -2
  41. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -6
  42. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -10
  43. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -1
  44. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -1
  45. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -1
  46. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -2
  47. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -1
  48. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -1
  49. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -1
  50. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -1
  51. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -3
  52. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -100
  53. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -1
  54. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -4
  55. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -3
  56. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -15
  57. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -22
  58. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -8
  59. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -4
  60. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -1
  61. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -3
  62. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -3
  63. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -17
  64. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -15
  65. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -11
  66. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -7
  67. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -3
  68. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -2
  69. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -4
  70. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -6
  71. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -30
  72. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/introspect.py +14 -0
  73. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/reports/GAP_ANALYSIS.md +28 -3
  74. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/reports/gap_report.json +1672 -10
  75. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/snapshots/athena_latest.json +230 -15
  76. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +4046 -3115
  77. athena_python_docx-0.6.1/tests/test_collapsed_range_format.py +190 -0
  78. athena_python_docx-0.6.1/tests/test_paragraph_text_len_cache.py +161 -0
  79. athena_python_docx-0.6.1/tests/test_silent_stub_add_paragraph_style.py +67 -0
  80. athena_python_docx-0.6.1/tests/test_silent_stub_add_run.py +90 -0
  81. athena_python_docx-0.6.1/tests/test_silent_stub_cell_add_paragraph.py +47 -0
  82. athena_python_docx-0.6.1/tests/test_silent_stub_comments_add_comment.py +71 -0
  83. athena_python_docx-0.6.1/tests/test_silent_stub_enum_section.py +83 -0
  84. athena_python_docx-0.6.1/tests/test_silent_stub_inline_shape.py +105 -0
  85. athena_python_docx-0.6.1/tests/test_silent_stub_insert_paragraph_before.py +61 -0
  86. athena_python_docx-0.6.1/tests/test_silent_stub_paragraph_strict.py +170 -0
  87. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_paragraph_style.py +17 -9
  88. athena_python_docx-0.6.1/tests/test_silent_stub_paragraph_style_strict.py +93 -0
  89. athena_python_docx-0.6.1/tests/test_silent_stub_parfmt.py +367 -0
  90. athena_python_docx-0.6.1/tests/test_silent_stub_row_col_cell.py +181 -0
  91. athena_python_docx-0.6.1/tests/test_silent_stub_run_add_break.py +82 -0
  92. athena_python_docx-0.6.1/tests/test_silent_stub_run_style.py +57 -0
  93. athena_python_docx-0.6.1/tests/test_silent_stub_run_style_strict.py +71 -0
  94. athena_python_docx-0.6.1/tests/test_silent_stub_run_text.py +71 -0
  95. athena_python_docx-0.6.1/tests/test_silent_stub_run_underline.py +123 -0
  96. athena_python_docx-0.6.1/tests/test_silent_stub_section_dimensions.py +96 -0
  97. athena_python_docx-0.6.1/tests/test_silent_stub_section_onoff.py +83 -0
  98. athena_python_docx-0.6.1/tests/test_silent_stub_table_layout.py +153 -0
  99. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/uv.lock +1 -1
  100. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/54_empty_everything.json +0 -6
  101. athena_python_docx-0.5.3/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -18
  102. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/.gitignore +0 -0
  103. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/CLAUDE.md +0 -0
  104. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/README.md +0 -0
  105. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_batching.py +0 -0
  106. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_buffer.py +0 -0
  107. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_http.py +0 -0
  108. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_http_doc.py +0 -0
  109. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_image_utils.py +0 -0
  110. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_ptc.py +0 -0
  111. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/api.py +0 -0
  112. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/client.py +0 -0
  113. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/commands.py +0 -0
  114. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/__init__.py +0 -0
  115. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/style.py +0 -0
  116. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/table.py +0 -0
  117. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/errors.py +0 -0
  118. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/exceptions.py +0 -0
  119. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/opc/__init__.py +0 -0
  120. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/opc/coreprops.py +0 -0
  121. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/revisions.py +0 -0
  122. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/settings.py +0 -0
  123. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/shared.py +0 -0
  124. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/__init__.py +0 -0
  125. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/style.py +0 -0
  126. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/styles.py +0 -0
  127. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/__init__.py +0 -0
  128. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/font.py +0 -0
  129. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/hyperlink.py +0 -0
  130. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/pagebreak.py +0 -0
  131. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/typing.py +0 -0
  132. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/publish.sh +0 -0
  133. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/release.sh +0 -0
  134. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/round_trip_smoke.py +0 -0
  135. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/__init__.py +0 -0
  136. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/conftest.py +0 -0
  137. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/METHODOLOGY.md +0 -0
  138. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/README.md +0 -0
  139. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/__init__.py +0 -0
  140. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ab_probe_cases.py +0 -0
  141. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ab_probe_runner.py +0 -0
  142. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/auto_gen_cases.py +0 -0
  143. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/binary_round_trip.py +0 -0
  144. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/cases.py +0 -0
  145. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/complex_cases.py +0 -0
  146. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/coverage_report.py +0 -0
  147. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/extract.py +0 -0
  148. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/extreme_cases.py +0 -0
  149. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/fake_session.py +0 -0
  150. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/local_runner.py +0 -0
  151. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/mega_cases.py +0 -0
  152. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshot.py +0 -0
  153. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  154. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  155. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  156. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  157. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  158. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
  159. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  160. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  161. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  162. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  163. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  164. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  165. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  166. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  167. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  168. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  169. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  170. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  171. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  172. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  173. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/23_nested_table.json +0 -0
  174. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  175. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  176. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  177. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  178. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  179. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  180. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  181. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  182. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  183. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  184. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  185. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  186. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  187. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  188. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  189. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  190. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  191. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  192. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  193. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -0
  194. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  195. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  196. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  197. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  198. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  199. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  200. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  201. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  202. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  203. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  204. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  205. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  206. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  207. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  208. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  209. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  210. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  211. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  212. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  213. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  214. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  215. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  216. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  217. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  218. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  219. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  220. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  221. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  222. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  223. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  224. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -0
  225. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  226. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  227. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  228. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  229. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  230. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  231. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  232. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  233. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  234. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  235. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  236. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  237. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  238. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  239. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  240. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  241. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  242. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  243. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  244. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  245. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  246. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -0
  247. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  248. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ours_spec.json +0 -0
  249. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/parity_crawl.py +0 -0
  250. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/parity_diff.json +0 -0
  251. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/real_world_cases.py +0 -0
  252. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/round_trip_tests.py +0 -0
  253. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/runner.py +0 -0
  254. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/stock_spec.json +0 -0
  255. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/README.md +0 -0
  256. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/__init__.py +0 -0
  257. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/baseline_gaps.json +0 -0
  258. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/compare.py +0 -0
  259. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/intentional_deviations.json +0 -0
  260. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/run_parity.py +0 -0
  261. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/test_parity_gap.py +0 -0
  262. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_batching_perf.py +0 -0
  263. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_buffer.py +0 -0
  264. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_command_dataclasses.py +0 -0
  265. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_commands.py +0 -0
  266. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_comments.py +0 -0
  267. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_document_create.py +0 -0
  268. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_http_transport.py +0 -0
  269. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_iter_inner_content.py +0 -0
  270. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_merged_cells.py +0 -0
  271. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_parity_misc.py +0 -0
  272. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_parity_round2.py +0 -0
  273. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_a_behavior.py +0 -0
  274. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_b_headers_footers.py +0 -0
  275. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_c_tables.py +0 -0
  276. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_pr19766_review_fixes.py +0 -0
  277. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_ptc.py +0 -0
  278. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_python_docx_api_parity.py +0 -0
  279. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_revisions.py +0 -0
  280. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_add_picture.py +0 -0
  281. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_comments_get.py +0 -0
  282. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_document_audit.py +0 -0
  283. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_document_element.py +0 -0
  284. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_font_audit.py +0 -0
  285. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_header_footer.py +0 -0
  286. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_hyperlink.py +0 -0
  287. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_misc.py +0 -0
  288. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_run_bool_setters.py +0 -0
  289. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_section_audit.py +0 -0
  290. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_settings.py +0 -0
  291. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_shared_audit.py +0 -0
  292. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_style.py +0 -0
  293. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_styles.py +0 -0
  294. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_audit.py +0 -0
  295. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_cell.py +0 -0
  296. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_dimensions.py +0 -0
  297. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_smoke_integration.py +0 -0
  298. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_acceptance.py +0 -0
  299. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_font.py +0 -0
  300. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_setters_contract.py +0 -0
  301. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_wire_contract.py +0 -0
  302. {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_zod_wire_contract.py +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.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.3"
9
+ __version__ = "0.6.1"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import flush_all
@@ -314,6 +314,26 @@ class Comments:
314
314
  Use :meth:`Document.add_comment` to thread a run-anchored
315
315
  target — this method creates an unanchored comment.
316
316
  """
317
+ # python-docx 1.x routes ``text`` / ``author`` / ``initials``
318
+ # through lxml's element setters which TypeError on non-str.
319
+ # Was: any value shipped to wire (text) or stashed as-is on
320
+ # the local info dict (author/initials) — caller's intent was
321
+ # lost when they passed a wrong type.
322
+ if not isinstance(text, str):
323
+ raise TypeError(
324
+ f"Comments.add_comment text requires str; got "
325
+ f"{type(text).__name__} {text!r}",
326
+ )
327
+ if not isinstance(author, str):
328
+ raise TypeError(
329
+ f"Comments.add_comment author requires str; got "
330
+ f"{type(author).__name__} {author!r}",
331
+ )
332
+ if initials is not None and not isinstance(initials, str):
333
+ raise TypeError(
334
+ f"Comments.add_comment initials requires str or None; "
335
+ f"got {type(initials).__name__} {initials!r}",
336
+ )
317
337
  result: object = run_sync(
318
338
  self._session.doc.comments.create({"text": text}),
319
339
  )
@@ -596,9 +596,24 @@ class Document:
596
596
 
597
597
  # Coerce ParagraphStyle instances to their style id so the rest
598
598
  # of this method can treat `style` as an Optional[str].
599
- style_str: str | None = (
600
- style.style_id if isinstance(style, ParagraphStyle) else style
601
- )
599
+ # python-docx 1.x accepts ``str | ParagraphStyle | None`` and
600
+ # raises ``TypeError`` at the style-lookup layer for anything
601
+ # else. Mirror that — the previous code accepted ``style`` as
602
+ # the literal value when it wasn't a ParagraphStyle, so e.g.
603
+ # ``add_paragraph(style=42)`` shipped ``42`` as the style id.
604
+ style_str: str | None
605
+ if style is None:
606
+ style_str = None
607
+ elif isinstance(style, ParagraphStyle):
608
+ style_str = style.style_id
609
+ elif isinstance(style, str):
610
+ style_str = style
611
+ else:
612
+ raise TypeError(
613
+ f"Document.add_paragraph style requires str, "
614
+ f"ParagraphStyle, or None; got "
615
+ f"{type(style).__name__} {style!r}",
616
+ )
602
617
 
603
618
  # Use Superdoc's canonical primitive `doc.create.paragraph`. It
604
619
  # accepts an `at` anchor and a `text` body; an empty `text` creates
@@ -624,8 +639,9 @@ class Document:
624
639
  # heavy lifting.
625
640
  normalized: str = self._normalize_text(text)
626
641
  has_control_chars = any(ch in "\t\n\r" for ch in normalized)
642
+ wire_text: str = "" if has_control_chars else normalized
627
643
  params: dict = {
628
- "text": "" if has_control_chars else normalized,
644
+ "text": wire_text,
629
645
  "at": {"kind": "documentEnd"},
630
646
  }
631
647
  # When inside ``with doc.batch():`` we pre-assign a client UUID
@@ -650,8 +666,13 @@ class Document:
650
666
  raise RuntimeError(
651
667
  f"Superdoc did not return a nodeId for add_paragraph: {result!r}",
652
668
  )
669
+ # Seed the text-length cache so the next ``p.add_run(...)``
670
+ # call can skip its ``get_node_by_id`` HTTP round-trip.
653
671
  para = Paragraph(
654
- session=self._session, node_id=node_id, node_type="paragraph",
672
+ session=self._session,
673
+ node_id=node_id,
674
+ node_type="paragraph",
675
+ text_len=len(wire_text),
655
676
  )
656
677
  if client_node_id is not None:
657
678
  self._register_proxy_for_batch(client_node_id, para)
@@ -722,6 +743,7 @@ class Document:
722
743
  session=self._session,
723
744
  node_id=node_id,
724
745
  node_type="paragraph",
746
+ text_len=len(wire_text),
725
747
  )
726
748
  if client_node_id is not None:
727
749
  self._register_proxy_for_batch(client_node_id, paragraph)
@@ -753,7 +775,10 @@ class Document:
753
775
  f"Superdoc did not return a nodeId for add_heading: {result!r}",
754
776
  )
755
777
  heading = Paragraph(
756
- session=self._session, node_id=node_id, node_type="heading",
778
+ session=self._session,
779
+ node_id=node_id,
780
+ node_type="heading",
781
+ text_len=len(wire_text),
757
782
  )
758
783
  if client_node_id is not None:
759
784
  self._register_proxy_for_batch(client_node_id, heading)
@@ -4,6 +4,17 @@ from __future__ import annotations
4
4
 
5
5
  from enum import Enum
6
6
 
7
+ from docx.enum.text import _warn_enum_coercion
8
+
9
+ __all__ = [
10
+ "WD_HEADER_FOOTER",
11
+ "WD_HEADER_FOOTER_INDEX",
12
+ "WD_ORIENT",
13
+ "WD_ORIENTATION",
14
+ "WD_SECTION",
15
+ "WD_SECTION_START",
16
+ ]
17
+
7
18
 
8
19
  class WD_ORIENTATION(Enum):
9
20
  PORTRAIT = "portrait"
@@ -31,6 +42,13 @@ class WD_SECTION_START(Enum):
31
42
  return "evenPage"
32
43
  if self == WD_SECTION_START.ODD_PAGE:
33
44
  return "oddPage"
45
+ if self == WD_SECTION_START.NEW_PAGE:
46
+ return "nextPage"
47
+ # NEW_COLUMN — SuperDoc 1.8 doesn't have a column-break section
48
+ # type, so we collapse to "nextPage" but emit
49
+ # PendingEnumCoercionWarning so callers don't silently get a
50
+ # page break when they asked for a column break.
51
+ _warn_enum_coercion(self, "nextPage")
34
52
  return "nextPage"
35
53
 
36
54
 
@@ -2,14 +2,62 @@
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
+ _INT_TO_ALIGN: "dict[int, str]" = {
17
+ 0: "LEFT",
18
+ 1: "CENTER",
19
+ 2: "RIGHT",
20
+ 3: "JUSTIFY",
21
+ 4: "DISTRIBUTE",
22
+ 5: "JUSTIFY_MED",
23
+ 7: "JUSTIFY_HI",
24
+ 8: "JUSTIFY_LOW",
25
+ 9: "THAI_JUSTIFY",
26
+ }
27
+
28
+
29
+ class PendingEnumCoercionWarning(UserWarning):
30
+ """Emitted when an enum member's :meth:`to_superdoc` collapses the
31
+ value to a different SuperDoc-supported primitive.
32
+
33
+ Examples:
34
+ - ``WD_ALIGN_PARAGRAPH.THAI_JUSTIFY.to_superdoc()`` returns
35
+ ``"justify"`` because SuperDoc 1.8's ``set_alignment`` rejects
36
+ ``thaiJustify``.
37
+ - ``WD_TAB_ALIGNMENT.CLEAR.to_superdoc()`` returns ``"left"``
38
+ because SuperDoc has no equivalent clear/end/num/start tab
39
+ vocabulary.
40
+
41
+ Tracked in ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``. Pin so a
42
+ future SuperDoc that lands the full vocabulary can flip the
43
+ coercion off and these warnings disappear.
44
+ """
45
+
46
+
47
+ def _warn_enum_coercion(enum_member: object, fallback: str) -> None:
48
+ """Emit a single warning identifying which enum member got
49
+ coerced to which SuperDoc primitive."""
50
+ warnings.warn(
51
+ f"{enum_member!r}.to_superdoc() returns {fallback!r} — "
52
+ f"SuperDoc 1.8 doesn't surface this value, so the wire ships "
53
+ f"the closest supported primitive. The visual result may "
54
+ f"differ from python-docx. Tracked in "
55
+ f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
56
+ PendingEnumCoercionWarning,
57
+ stacklevel=3,
58
+ )
59
+
60
+
13
61
  class WD_ALIGN_PARAGRAPH(Enum):
14
62
  """Paragraph alignment (justification)."""
15
63
 
@@ -23,10 +71,27 @@ class WD_ALIGN_PARAGRAPH(Enum):
23
71
  JUSTIFY_LOW = "justifyLow"
24
72
  THAI_JUSTIFY = "thaiJustify"
25
73
 
74
+ @classmethod
75
+ def from_int(cls, value: int) -> "WD_ALIGN_PARAGRAPH | None":
76
+ """Coerce a python-docx-style int alignment to the enum.
77
+
78
+ python-docx 1.x's ``WD_ALIGN_PARAGRAPH`` is keyed on int (its
79
+ ``BaseXmlEnum`` mapping: LEFT=0, CENTER=1, RIGHT=2, JUSTIFY=3,
80
+ DISTRIBUTE=4, JUSTIFY_MED=5, JUSTIFY_HI=7, JUSTIFY_LOW=8,
81
+ THAI_JUSTIFY=9). Callers passing ``paragraph.alignment = 1``
82
+ get CENTER. We mirror that without changing our enum's
83
+ string-valued definition.
84
+ """
85
+ name = _INT_TO_ALIGN.get(value)
86
+ return getattr(cls, name) if name is not None else None
87
+
26
88
  def to_superdoc(self) -> str:
27
89
  # Superdoc only supports left/center/right/justify; coerce the
28
90
  # distributed/thai variants to "justify" so set_alignment doesn't
29
- # reject them.
91
+ # reject them. Emit PendingEnumCoercionWarning so the caller
92
+ # learns the wire-level intent was downgraded (silently shipping
93
+ # "justify" when the user asked for thaiJustify is the silent
94
+ # stub the parity loop is hunting).
30
95
  if self in (
31
96
  WD_ALIGN_PARAGRAPH.DISTRIBUTE,
32
97
  WD_ALIGN_PARAGRAPH.JUSTIFY_MED,
@@ -34,6 +99,7 @@ class WD_ALIGN_PARAGRAPH(Enum):
34
99
  WD_ALIGN_PARAGRAPH.JUSTIFY_LOW,
35
100
  WD_ALIGN_PARAGRAPH.THAI_JUSTIFY,
36
101
  ):
102
+ _warn_enum_coercion(self, "justify")
37
103
  return "justify"
38
104
  return self.value
39
105
 
@@ -82,6 +148,10 @@ class WD_TAB_ALIGNMENT(Enum):
82
148
  START = "start"
83
149
 
84
150
  def to_superdoc(self) -> str:
151
+ # Superdoc only supports left/center/right/decimal/bar for tab
152
+ # alignment. ``LIST`` / ``CLEAR`` / ``END`` / ``NUM`` / ``START``
153
+ # are upstream-only — emit PendingEnumCoercionWarning so callers
154
+ # learn the wire-level intent was downgraded to ``"left"``.
85
155
  if self in (
86
156
  WD_TAB_ALIGNMENT.LIST,
87
157
  WD_TAB_ALIGNMENT.CLEAR,
@@ -89,6 +159,7 @@ class WD_TAB_ALIGNMENT(Enum):
89
159
  WD_TAB_ALIGNMENT.NUM,
90
160
  WD_TAB_ALIGNMENT.START,
91
161
  ):
162
+ _warn_enum_coercion(self, "left")
92
163
  return "left"
93
164
  return self.value
94
165
 
@@ -83,6 +83,66 @@ def _emu_to_pt(emu: int) -> float:
83
83
  return emu / 12700.0
84
84
 
85
85
 
86
+ def _reject_none_dimension(prop: str, value: object) -> None:
87
+ """Raise ``TypeError`` if ``value`` is None for a dimension setter
88
+ that python-docx 1.2.0 doesn't accept None for.
89
+
90
+ Upstream ``Section.page_width = None`` (and every margin /
91
+ header_distance / footer_distance / gutter setter) routes through
92
+ ``Emu(value).twips`` which raises ``TypeError`` on ``None``. Our
93
+ setters previously early-returned silently, swallowing the
94
+ intent. Raise to match upstream behavior — callers who actually
95
+ want a clear must pass ``Inches(0)`` (or similar) explicitly.
96
+ """
97
+ if value is None:
98
+ raise TypeError(
99
+ f"Section.{prop} = None is not supported. python-docx "
100
+ f"1.2.0 raises TypeError here too — its Emu(None).twips "
101
+ f"fails with the same shape. Pass an explicit Length "
102
+ f"(e.g. Inches(0)) if you want to zero the dimension."
103
+ )
104
+
105
+
106
+ class PendingSectionOnOffClearWarning(UserWarning):
107
+ """Emitted when ``Section.different_first_page_header_footer = None``.
108
+
109
+ python-docx 1.x semantics: ``None`` clears the OOXML
110
+ ``<w:titlePg/>`` element back to inherited. SuperDoc 1.8's
111
+ ``sections.set_title_page`` only accepts ``enabled: bool`` — the
112
+ wire can't represent the clear-intent. The warning surfaces
113
+ silent-divergence. Tracked in
114
+ ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``.
115
+ """
116
+
117
+
118
+ def _warn_section_onoff_clear(prop: str) -> None:
119
+ warnings.warn(
120
+ f"Section.{prop} = None was IGNORED — SuperDoc 1.8 has no "
121
+ f"clear-op for this OnOff property. The section keeps its "
122
+ f"previous value. Tracked in "
123
+ f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
124
+ PendingSectionOnOffClearWarning,
125
+ stacklevel=3,
126
+ )
127
+
128
+
129
+ def _require_section_bool(prop: str, value: object) -> bool:
130
+ """Reject non-bool input on Section OnOff setters.
131
+
132
+ python-docx 1.x's ``_OnOff`` typed-attribute setter raises
133
+ ``ValueError`` for non-bool input. Our previous ``bool(value)``
134
+ coercion silently turned ``"yes"`` / ``1`` / ``[]`` into True/False
135
+ without surfacing the type mismatch.
136
+ """
137
+ if not isinstance(value, bool):
138
+ raise TypeError(
139
+ f"Section.{prop} requires bool or None; got "
140
+ f"{type(value).__name__} {value!r}. python-docx 1.x's "
141
+ f"``_OnOff`` setter rejects truthy non-bool here too.",
142
+ )
143
+ return value
144
+
145
+
86
146
  class Section:
87
147
  """A document section — page size, margins, headers/footers, break type."""
88
148
 
@@ -124,8 +184,7 @@ class Section:
124
184
 
125
185
  @page_width.setter
126
186
  def page_width(self, value: "Length | int | None") -> None:
127
- if value is None:
128
- return
187
+ _reject_none_dimension("page_width", value)
129
188
  pt = _emu_to_pt(_emu_from(value))
130
189
  self._set_page_setup(width=pt)
131
190
 
@@ -140,8 +199,7 @@ class Section:
140
199
 
141
200
  @page_height.setter
142
201
  def page_height(self, value: "Length | int | None") -> None:
143
- if value is None:
144
- return
202
+ _reject_none_dimension("page_height", value)
145
203
  pt = _emu_to_pt(_emu_from(value))
146
204
  self._set_page_setup(height=pt)
147
205
 
@@ -201,8 +259,7 @@ class Section:
201
259
 
202
260
  @left_margin.setter
203
261
  def left_margin(self, value: "Length | int | None") -> None:
204
- if value is None:
205
- return
262
+ _reject_none_dimension("left_margin", value)
206
263
  self._set_margins(left=_emu_to_pt(_emu_from(value)))
207
264
 
208
265
  @property
@@ -211,8 +268,7 @@ class Section:
211
268
 
212
269
  @right_margin.setter
213
270
  def right_margin(self, value: "Length | int | None") -> None:
214
- if value is None:
215
- return
271
+ _reject_none_dimension("right_margin", value)
216
272
  self._set_margins(right=_emu_to_pt(_emu_from(value)))
217
273
 
218
274
  @property
@@ -221,8 +277,7 @@ class Section:
221
277
 
222
278
  @top_margin.setter
223
279
  def top_margin(self, value: "Length | int | None") -> None:
224
- if value is None:
225
- return
280
+ _reject_none_dimension("top_margin", value)
226
281
  self._set_margins(top=_emu_to_pt(_emu_from(value)))
227
282
 
228
283
  @property
@@ -231,8 +286,7 @@ class Section:
231
286
 
232
287
  @bottom_margin.setter
233
288
  def bottom_margin(self, value: "Length | int | None") -> None:
234
- if value is None:
235
- return
289
+ _reject_none_dimension("bottom_margin", value)
236
290
  self._set_margins(bottom=_emu_to_pt(_emu_from(value)))
237
291
 
238
292
  @property
@@ -241,8 +295,7 @@ class Section:
241
295
 
242
296
  @gutter.setter
243
297
  def gutter(self, value: "Length | int | None") -> None:
244
- if value is None:
245
- return
298
+ _reject_none_dimension("gutter", value)
246
299
  self._set_margins(gutter=_emu_to_pt(_emu_from(value)))
247
300
 
248
301
  @property
@@ -256,8 +309,7 @@ class Section:
256
309
 
257
310
  @header_distance.setter
258
311
  def header_distance(self, value: "Length | int | None") -> None:
259
- if value is None:
260
- return
312
+ _reject_none_dimension("header_distance", value)
261
313
  run_sync(
262
314
  self._session.doc.sections.set_header_footer_margins(
263
315
  {"target": self._address, "header": _emu_to_pt(_emu_from(value))},
@@ -275,8 +327,7 @@ class Section:
275
327
 
276
328
  @footer_distance.setter
277
329
  def footer_distance(self, value: "Length | int | None") -> None:
278
- if value is None:
279
- return
330
+ _reject_none_dimension("footer_distance", value)
280
331
  run_sync(
281
332
  self._session.doc.sections.set_header_footer_margins(
282
333
  {"target": self._address, "footer": _emu_to_pt(_emu_from(value))},
@@ -335,14 +386,18 @@ class Section:
335
386
  @different_first_page_header_footer.setter
336
387
  def different_first_page_header_footer(self, value: bool | None) -> None:
337
388
  if value is None:
389
+ _warn_section_onoff_clear("different_first_page_header_footer")
338
390
  return
391
+ enabled = _require_section_bool(
392
+ "different_first_page_header_footer", value
393
+ )
339
394
  run_sync(
340
395
  self._session.doc.sections.set_title_page(
341
396
  # SuperDoc's wire field is ``enabled`` (DocSectionsSet
342
397
  # TitlePageParams). The earlier ``titlePage`` name was
343
398
  # rejected silently because the apps/api applier punts
344
399
  # SuperDoc's strict types via ``AnyDoc``.
345
- {"target": self._address, "enabled": bool(value)},
400
+ {"target": self._address, "enabled": enabled},
346
401
  ),
347
402
  )
348
403
 
@@ -622,8 +677,20 @@ class _HeaderFooter:
622
677
  style_str = None
623
678
  elif isinstance(style, ParagraphStyle):
624
679
  style_str = style.style_id
680
+ elif isinstance(style, str):
681
+ style_str = style
625
682
  else:
626
- style_str = str(style)
683
+ # python-docx 1.x's ``add_paragraph(style=...)`` accepts
684
+ # ``str | ParagraphStyle | None`` and raises ``TypeError``
685
+ # at the style-lookup layer for anything else. The
686
+ # previous ``str(style)`` silently shipped garbage like
687
+ # ``<MyStyle object at 0x...>`` as a style id, which
688
+ # SuperDoc would swallow or reject without a clear signal.
689
+ raise TypeError(
690
+ f"_HeaderFooter.add_paragraph style requires str, "
691
+ f"ParagraphStyle, or None; got "
692
+ f"{type(style).__name__} {style!r}",
693
+ )
627
694
 
628
695
  result: object = run_sync(
629
696
  self._section._session.doc.create.paragraph(
@@ -7,6 +7,7 @@ to image binary / metadata round-trips through `doc.images.get`.
7
7
  from __future__ import annotations
8
8
 
9
9
  import base64
10
+ import warnings
10
11
  from typing import TYPE_CHECKING
11
12
 
12
13
  from docx._batching import run_sync
@@ -16,6 +17,29 @@ if TYPE_CHECKING:
16
17
  from docx.client import Session
17
18
 
18
19
 
20
+ class PendingInlineShapeClearWarning(UserWarning):
21
+ """Emitted when ``InlineShape.width`` or ``.height`` is set to
22
+ ``None`` (python-docx semantics: "revert to natural sizing").
23
+
24
+ SuperDoc 1.8 has no clear-op for image dimensions — its
25
+ ``images.setSize`` requires explicit ``width`` and ``height``. The
26
+ SDK can't represent a "revert to natural" intent on the wire, so
27
+ ``image.width = None`` is a no-op. The warning surfaces the
28
+ silent-divergence pattern so agent runs see the gap. Tracked in
29
+ ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``.
30
+ """
31
+
32
+
33
+ def _warn_inline_shape_clear(prop: str) -> None:
34
+ warnings.warn(
35
+ f"InlineShape.{prop} = None was IGNORED — SuperDoc 1.8 has no "
36
+ f"clear-op for image dimensions. The image keeps its previous "
37
+ f"size. Tracked in docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
38
+ PendingInlineShapeClearWarning,
39
+ stacklevel=3,
40
+ )
41
+
42
+
19
43
  def _strip_data_uri(src: str) -> tuple[bytes, str | None]:
20
44
  """If ``src`` is a ``data:`` URI, return (decoded_bytes, mime).
21
45
  Otherwise return ``(b"", None)``."""
@@ -63,6 +87,7 @@ class InlineShape:
63
87
  @width.setter
64
88
  def width(self, value: "Length | int | None") -> None:
65
89
  if value is None:
90
+ _warn_inline_shape_clear("width")
66
91
  return
67
92
  pt: float = value.pt if isinstance(value, Length) else float(value) / 12700.0
68
93
  h = self.height
@@ -92,6 +117,7 @@ class InlineShape:
92
117
  @height.setter
93
118
  def height(self, value: "Length | int | None") -> None:
94
119
  if value is None:
120
+ _warn_inline_shape_clear("height")
95
121
  return
96
122
  pt: float = value.pt if isinstance(value, Length) else float(value) / 12700.0
97
123
  w = self.width