athena-python-docx 0.43.0__tar.gz → 0.45.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 (503) hide show
  1. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/PKG-INFO +8 -1
  2. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/README.md +7 -0
  3. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/__init__.py +1 -1
  4. athena_python_docx-0.45.0/docx/_asset_token.py +379 -0
  5. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_http.py +114 -2
  6. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_http_doc.py +139 -33
  7. athena_python_docx-0.45.0/docx/_public_create.py +270 -0
  8. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/client.py +12 -9
  9. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/document.py +5 -1
  10. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/pyproject.toml +1 -1
  11. athena_python_docx-0.45.0/tests/test_asset_tokens.py +483 -0
  12. athena_python_docx-0.45.0/tests/test_public_create.py +473 -0
  13. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/uv.lock +1 -1
  14. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/.gitignore +0 -0
  15. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/AGENTS.md +0 -0
  16. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/CLAUDE.md +0 -0
  17. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/DOCX_EXEC_LAB.md +0 -0
  18. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_athena_extension.py +0 -0
  19. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_batching.py +0 -0
  20. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_buffer.py +0 -0
  21. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_capabilities.py +0 -0
  22. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_citations.py +0 -0
  23. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_execution.py +0 -0
  24. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_image_utils.py +0 -0
  25. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_postproc.py +0 -0
  26. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_proxy.py +0 -0
  27. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_ptc.py +0 -0
  28. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_references.py +0 -0
  29. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_run_order.py +0 -0
  30. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_table_styles.py +0 -0
  31. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_timeouts.py +0 -0
  32. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_tracked.py +0 -0
  33. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/_xml_text.py +0 -0
  34. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/api.py +0 -0
  35. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/blkcntnr.py +0 -0
  36. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/bookmarks.py +0 -0
  37. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/charts.py +0 -0
  38. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/commands.py +0 -0
  39. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/comments.py +0 -0
  40. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/drawing/__init__.py +0 -0
  41. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/__init__.py +0 -0
  42. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/base.py +0 -0
  43. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/dml.py +0 -0
  44. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/section.py +0 -0
  45. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/shape.py +0 -0
  46. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/style.py +0 -0
  47. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/table.py +0 -0
  48. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/enum/text.py +0 -0
  49. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/errors.py +0 -0
  50. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/exceptions.py +0 -0
  51. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/fields.py +0 -0
  52. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/footnotes.py +0 -0
  53. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/image/__init__.py +0 -0
  54. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/image/exceptions.py +0 -0
  55. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/image/image.py +0 -0
  56. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/math.py +0 -0
  57. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/opc/__init__.py +0 -0
  58. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/opc/coreprops.py +0 -0
  59. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/oxml/__init__.py +0 -0
  60. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/revisions.py +0 -0
  61. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/sdt.py +0 -0
  62. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/section.py +0 -0
  63. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/session.py +0 -0
  64. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/settings.py +0 -0
  65. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/shape.py +0 -0
  66. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/shared.py +0 -0
  67. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/styles/__init__.py +0 -0
  68. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/styles/_table.py +0 -0
  69. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/styles/latent.py +0 -0
  70. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/styles/style.py +0 -0
  71. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/styles/styles.py +0 -0
  72. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/table.py +0 -0
  73. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/__init__.py +0 -0
  74. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/font.py +0 -0
  75. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/hyperlink.py +0 -0
  76. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/pagebreak.py +0 -0
  77. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/paragraph.py +0 -0
  78. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/parfmt.py +0 -0
  79. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/run.py +0 -0
  80. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/text/tabstops.py +0 -0
  81. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/toc.py +0 -0
  82. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/docx/typing.py +0 -0
  83. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab.py +0 -0
  84. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  85. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  86. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_server.py +0 -0
  87. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/dump_wire_fixtures.py +0 -0
  88. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/release.sh +0 -0
  89. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/round_trip_smoke.py +0 -0
  90. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/smoke_test_block_not_found.py +0 -0
  91. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/scripts/validate_find_replace_asset.py +0 -0
  92. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/__init__.py +0 -0
  93. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/conftest.py +0 -0
  94. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/METHODOLOGY.md +0 -0
  95. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/README.md +0 -0
  96. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/__init__.py +0 -0
  97. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/__init__.py +0 -0
  98. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/agent_documents.py +0 -0
  99. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
  100. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
  101. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
  102. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
  103. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
  104. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/picture_runs.py +0 -0
  105. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
  106. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/return_types.py +0 -0
  107. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
  108. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
  109. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe_cases.py +0 -0
  110. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe_runner.py +0 -0
  111. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/auto_gen_cases.py +0 -0
  112. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/binary_round_trip.py +0 -0
  113. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/cases.py +0 -0
  114. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/complex_cases.py +0 -0
  115. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/coverage_report.py +0 -0
  116. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/extract.py +0 -0
  117. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/extreme_cases.py +0 -0
  118. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/fake_session.py +0 -0
  119. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/README.md +0 -0
  120. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  121. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  122. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  123. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  124. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  125. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/local_runner.py +0 -0
  126. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/mega_cases.py +0 -0
  127. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshot.py +0 -0
  128. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  129. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  130. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  131. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  132. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  133. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  134. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  135. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  136. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  137. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  138. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  139. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
  140. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  141. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  142. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  143. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  144. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  145. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  146. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  147. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  148. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
  149. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  150. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
  151. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  152. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  153. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  154. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  155. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  156. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  157. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  158. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  159. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  160. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  161. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  162. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  163. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  164. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  165. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  166. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
  167. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  168. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  169. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  170. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
  171. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  172. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  173. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  174. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  175. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  176. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  177. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  178. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  179. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
  180. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  181. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  182. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  183. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  184. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  185. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  186. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  187. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  188. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  189. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
  190. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  191. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  192. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  193. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  194. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  195. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  196. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  197. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  198. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  199. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  200. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  201. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  202. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  203. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  204. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  205. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  206. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  207. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
  208. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  209. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  210. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  211. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  212. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
  213. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  214. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
  215. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  216. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  217. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  218. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
  219. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  220. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  221. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  222. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  223. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  224. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  225. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
  226. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  227. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  228. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  229. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  230. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  231. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
  232. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  233. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  234. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  235. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  236. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  237. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  238. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  239. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  240. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  241. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  242. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  243. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  244. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  245. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  246. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  247. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  248. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  249. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  250. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  251. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  252. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  253. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  254. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  255. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  256. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  257. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  258. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  259. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  260. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  261. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  262. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  263. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  264. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  265. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  266. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  267. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  268. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  269. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  270. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  271. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  272. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  273. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  274. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  275. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  276. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  277. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  278. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  279. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  280. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/ours_spec.json +0 -0
  281. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/parity_crawl.py +0 -0
  282. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/parity_diff.json +0 -0
  283. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/real_world_cases.py +0 -0
  284. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/round_trip_tests.py +0 -0
  285. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/stock_spec.json +0 -0
  286. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  287. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fixtures/field_reads.json +0 -0
  288. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fixtures/note_reference_reads.json +0 -0
  289. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fixtures/ruby_reads.json +0 -0
  290. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/fixtures/symbol_reads.json +0 -0
  291. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/__init__.py +0 -0
  292. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/baseline.json +0 -0
  293. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/fixture_scripts.py +0 -0
  294. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/reader.py +0 -0
  295. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/runner.py +0 -0
  296. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/sdk_driver.py +0 -0
  297. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/stock_driver.py +0 -0
  298. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/live/test_live_runner.py +0 -0
  299. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/README.md +0 -0
  300. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/__init__.py +0 -0
  301. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/baseline_gaps.json +0 -0
  302. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/compare.py +0 -0
  303. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/intentional_deviations.json +0 -0
  304. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/introspect.py +0 -0
  305. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  306. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/reports/gap_report.json +0 -0
  307. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/run_parity.py +0 -0
  308. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/snapshots/athena_latest.json +0 -0
  309. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  310. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/parity/test_parity_gap.py +0 -0
  311. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_add_section.py +0 -0
  312. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_add_section_extract_items.py +0 -0
  313. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_alignment_values.py +0 -0
  314. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  315. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_athena_extensions_contract.py +0 -0
  316. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_athena_extensions_registry.py +0 -0
  317. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_batch_chunking.py +0 -0
  318. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_batching_perf.py +0 -0
  319. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_battery_cases.py +0 -0
  320. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_block_not_found_error.py +0 -0
  321. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_buffer.py +0 -0
  322. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  323. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_add_table_not_supported.py +0 -0
  324. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_borders_spec.py +0 -0
  325. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_fastpath_runs.py +0 -0
  326. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  327. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  328. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_format_stash.py +0 -0
  329. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  330. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_run_guard.py +0 -0
  331. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_merge.py +0 -0
  332. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_nested_tables.py +0 -0
  333. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_paragraphs_listed.py +0 -0
  334. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  335. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_cell_text_replace_semantics.py +0 -0
  336. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_citations.py +0 -0
  337. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_collapsed_range_format.py +0 -0
  338. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_color_format_theme.py +0 -0
  339. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_command_dataclasses.py +0 -0
  340. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_commands.py +0 -0
  341. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_comment_paragraphs.py +0 -0
  342. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_comments.py +0 -0
  343. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_comments_first_read.py +0 -0
  344. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_content_control_value.py +0 -0
  345. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_core_properties.py +0 -0
  346. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_create_workspace.py +0 -0
  347. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_asset_id_property.py +0 -0
  348. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_clear.py +0 -0
  349. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_create.py +0 -0
  350. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_create_from_template.py +0 -0
  351. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_factory_validation.py +0 -0
  352. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_document_settings_session_open.py +0 -0
  353. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_docx_exec_lab.py +0 -0
  354. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_docx_exec_lab_server.py +0 -0
  355. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_drawing_image.py +0 -0
  356. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  357. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_empty_hyperlinks.py +0 -0
  358. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_enum_parity.py +0 -0
  359. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_execution_scope.py +0 -0
  360. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_export_docx_clean.py +0 -0
  361. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_export_rescue_anchors.py +0 -0
  362. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  363. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_field_refresh.py +0 -0
  364. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_field_runs.py +0 -0
  365. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_find_replace_session_open.py +0 -0
  366. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_flushed_write_failures.py +0 -0
  367. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_http_transport.py +0 -0
  368. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_hyperlink_coalescing.py +0 -0
  369. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_image_url_data_uri.py +0 -0
  370. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_inline_page_break.py +0 -0
  371. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_alt_text.py +0 -0
  372. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_size.py +0 -0
  373. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_type.py +0 -0
  374. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_inline_shapes_floating.py +0 -0
  375. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_insert_deferred.py +0 -0
  376. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_iter_inner_content.py +0 -0
  377. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_latent_style_writes.py +0 -0
  378. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_line_clear_break.py +0 -0
  379. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_list_styles.py +0 -0
  380. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_listed_paragraph_reads.py +0 -0
  381. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_literal_no_break_hyphens.py +0 -0
  382. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_literal_soft_hyphens.py +0 -0
  383. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_merged_cell_identity.py +0 -0
  384. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  385. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_merged_cells.py +0 -0
  386. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_missing_modules.py +0 -0
  387. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_nested_table_refused.py +0 -0
  388. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  389. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_oxml_shim.py +0 -0
  390. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_page_break.py +0 -0
  391. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_paragraph_delete.py +0 -0
  392. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_paragraph_indent_reads.py +0 -0
  393. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  394. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_paragraph_text_empty_run.py +0 -0
  395. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_paragraph_text_len_cache.py +0 -0
  396. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_parfmt_clears.py +0 -0
  397. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_parity_misc.py +0 -0
  398. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_parity_round2.py +0 -0
  399. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_partial_failure_cascade.py +0 -0
  400. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  401. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_phase_a_behavior.py +0 -0
  402. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_phase_b_headers_footers.py +0 -0
  403. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_phase_c_tables.py +0 -0
  404. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_positional_cell_id.py +0 -0
  405. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  406. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  407. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_postproc_ref_restore.py +0 -0
  408. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_pr19766_review_fixes.py +0 -0
  409. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_proxy_equality.py +0 -0
  410. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_ptc.py +0 -0
  411. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_python_docx_api_parity.py +0 -0
  412. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_read_run_ranges.py +0 -0
  413. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_rendered_page_breaks.py +0 -0
  414. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_repeated_node_read.py +0 -0
  415. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_restart_numbering.py +0 -0
  416. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_revisions.py +0 -0
  417. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_round_trip_smoke_script.py +0 -0
  418. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  419. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_add_picture_anchor.py +0 -0
  420. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_break_inner_content.py +0 -0
  421. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_edges.py +0 -0
  422. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_formatting_wire.py +0 -0
  423. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_identity.py +0 -0
  424. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_later_runs.py +0 -0
  425. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_mark_inheritance.py +0 -0
  426. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_page_number_blocks.py +0 -0
  427. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_table_style_objects.py +0 -0
  428. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_text_python_docx.py +0 -0
  429. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  430. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_run_unmodeled_toggles.py +0 -0
  431. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_sdk_reads_served.py +0 -0
  432. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_section_read_lengths.py +0 -0
  433. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_sections_empty_list.py +0 -0
  434. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  435. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_picture.py +0 -0
  436. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_run.py +0 -0
  437. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  438. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  439. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_comments_get.py +0 -0
  440. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_document_audit.py +0 -0
  441. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_document_element.py +0 -0
  442. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_enum_section.py +0 -0
  443. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_font_audit.py +0 -0
  444. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_header_footer.py +0 -0
  445. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_hyperlink.py +0 -0
  446. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_inline_shape.py +0 -0
  447. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  448. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_misc.py +0 -0
  449. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  450. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  451. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  452. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_parfmt.py +0 -0
  453. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  454. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_add_break.py +0 -0
  455. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  456. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_style.py +0 -0
  457. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  458. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_text.py +0 -0
  459. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_underline.py +0 -0
  460. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_audit.py +0 -0
  461. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  462. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_onoff.py +0 -0
  463. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_settings.py +0 -0
  464. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_shared_audit.py +0 -0
  465. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_style.py +0 -0
  466. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_styles.py +0 -0
  467. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_audit.py +0 -0
  468. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_cell.py +0 -0
  469. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  470. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_layout.py +0 -0
  471. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_smoke_integration.py +0 -0
  472. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_acceptance.py +0 -0
  473. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_delete.py +0 -0
  474. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_font.py +0 -0
  475. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_formatting_writes.py +0 -0
  476. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_metadata_writes.py +0 -0
  477. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_names.py +0 -0
  478. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_resolution.py +0 -0
  479. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_setters_contract.py +0 -0
  480. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_tab_stops.py +0 -0
  481. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_style_tab_stops_read.py +0 -0
  482. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  483. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_tab_stop_writes.py +0 -0
  484. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_add_row_grid_row.py +0 -0
  485. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_anchors.py +0 -0
  486. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_clears.py +0 -0
  487. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_direction.py +0 -0
  488. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_length_reads.py +0 -0
  489. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_listing_reads.py +0 -0
  490. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_read_reuse.py +0 -0
  491. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_set_cell_perf.py +0 -0
  492. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_table_style_id_resolution.py +0 -0
  493. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_temporarily_unavailable.py +0 -0
  494. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_text_control_characters.py +0 -0
  495. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_tracked_revisions_offsets.py +0 -0
  496. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_unmapped_alignment_reads.py +0 -0
  497. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_uv_lock_version.py +0 -0
  498. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  499. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_versioned_read_reuse.py +0 -0
  500. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_wire_contract.py +0 -0
  501. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_xml_attr_guard.py +0 -0
  502. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_xml_incompatible_text.py +0 -0
  503. {athena_python_docx-0.43.0 → athena_python_docx-0.45.0}/tests/test_zod_wire_contract.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-docx
3
- Version: 0.43.0
3
+ Version: 0.45.0
4
4
  Summary: Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack
5
5
  Project-URL: Homepage, https://athenaintelligence.ai
6
6
  Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
@@ -81,6 +81,13 @@ Required when connecting to DOCX Studio (set by the Athena backend in the `execu
81
81
  - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
82
82
  - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
83
83
 
84
+ Without `ATHENA_DOCX_API_KEY` (and without `api_key=`), the SDK uses
85
+ `ATHENA_API_KEY`. When `ATHENA_API_URL` is set too (the bare Athena URL or one
86
+ ending in `/api/v0`), an opened document's calls carry a 15-minute token Athena
87
+ mints for that document alone (`POST /api/v0/assets/{asset_id}/studio-token`),
88
+ read-only for reads; `Document.create()` and its upload still send the key
89
+ (`docx/_asset_token.py`).
90
+
84
91
  ## License
85
92
 
86
93
  MIT
@@ -56,6 +56,13 @@ Required when connecting to DOCX Studio (set by the Athena backend in the `execu
56
56
  - `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
57
57
  - `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
58
58
 
59
+ Without `ATHENA_DOCX_API_KEY` (and without `api_key=`), the SDK uses
60
+ `ATHENA_API_KEY`. When `ATHENA_API_URL` is set too (the bare Athena URL or one
61
+ ending in `/api/v0`), an opened document's calls carry a 15-minute token Athena
62
+ mints for that document alone (`POST /api/v0/assets/{asset_id}/studio-token`),
63
+ read-only for reads; `Document.create()` and its upload still send the key
64
+ (`docx/_asset_token.py`).
65
+
59
66
  ## License
60
67
 
61
68
  MIT
@@ -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.43.0"
9
+ __version__ = "0.45.0"
10
10
 
11
11
  from docx.api import Document
12
12
  from docx._buffer import discard_all, flush_all
@@ -0,0 +1,379 @@
1
+ """Per-document DOCX Studio tokens, minted from Athena's public API.
2
+
3
+ A call on an existing Word document reaches DOCX Studio with, in this order:
4
+
5
+ 1. the ``api_key`` the caller passed;
6
+ 2. the studio's own key, ``ATHENA_DOCX_API_KEY``;
7
+ 3. when ``ATHENA_API_KEY`` and ``ATHENA_API_URL`` are both set, a token for that
8
+ document alone, minted by
9
+ ``POST {ATHENA_API_URL}/api/v0/assets/{asset_id}/studio-token`` with
10
+ ``X-API-KEY: $ATHENA_API_KEY`` and sent as ``Authorization: Bearer``. It names
11
+ the caller, the document, one access level and DOCX Studio, and lasts 15
12
+ minutes;
13
+ 4. otherwise ``ATHENA_API_KEY`` itself, as before.
14
+
15
+ Creating a document (``Document.create``, its upload) keeps the key of 1, 2 or
16
+ 4: a document that does not exist yet has no token. In case 3 Athena's public
17
+ API creates it instead (``docx._public_create``). A token goes only to its own
18
+ document's routes.
19
+
20
+ A token is minted once per (agora, key, asset, access) for the whole process,
21
+ again 90 seconds before it expires, and once more when the studio answers 401.
22
+ A read mints a read-only token (``{"access": "view"}``: the version check, the
23
+ layout, page renders, the clean export), a write a read-write one
24
+ (``{"access": "edit"}``, which Athena grants only to a caller who may edit).
25
+ Every command batch is a write to DOCX Studio, whose ``/commands`` route needs
26
+ edit access even for a batch that only queries. ``ATHENA_API_URL`` ends in
27
+ ``/api/v0`` inside an Athena computer and is the bare agora URL in a session VM
28
+ or locally; both work.
29
+
30
+ Athena's refusals (400, 401, 403, 404, 422) raise at once, without a retry. A
31
+ deployment that signs no asset tokens answers 503: the client then uses the
32
+ studio key when one is set, and otherwise raises an error that names it. An
33
+ Athena older than the route answers FastAPI's bare 404 (``{"detail": "Not
34
+ Found"}``): the client then sends ``ATHENA_API_KEY``, as before the route.
35
+ """
36
+
37
+ from __future__ import annotations
38
+
39
+ import hashlib
40
+ import inspect
41
+ import os
42
+ import threading
43
+ import time
44
+ from collections import OrderedDict
45
+ from dataclasses import dataclass, field
46
+ from typing import Any
47
+ from urllib.parse import quote
48
+
49
+ import requests
50
+ from requests.adapters import HTTPAdapter
51
+ from urllib3.util.retry import Retry
52
+
53
+ from docx.errors import (
54
+ AuthenticationError,
55
+ DocxError,
56
+ DocxStudioTemporarilyUnavailable,
57
+ NotFoundError,
58
+ SessionError,
59
+ )
60
+
61
+ API_KEY_ENV = "ATHENA_API_KEY"
62
+ API_URL_ENV = "ATHENA_API_URL"
63
+ STUDIO_KEY_ENV = "ATHENA_DOCX_API_KEY"
64
+ #: The token audience DOCX Studio verifies.
65
+ AUDIENCE = "docx-studio"
66
+ TOKEN_PREFIX = "aat_"
67
+ PUBLIC_API_PREFIX = "/api/v0"
68
+
69
+ #: The access a token is minted for.
70
+ VIEW = "view"
71
+ EDIT = "edit"
72
+
73
+ #: Minted again this long before Athena's ``expires_at_ms``.
74
+ REFRESH_BEFORE_EXPIRY_SECONDS = 90.0
75
+ #: The longest a token is held, whatever the local clock says (Athena's lifetime).
76
+ MAX_LIFETIME_SECONDS = 15 * 60.0
77
+ #: The shortest, so a clock running ahead of Athena's cannot mint per call.
78
+ MIN_LIFETIME_SECONDS = 30.0
79
+ MINT_TIMEOUT_SECONDS = 30.0
80
+ _MAX_CACHED_TOKENS = 256
81
+ _LOCK_STRIPES = 16
82
+
83
+ _KIND_BY_AUDIENCE = {
84
+ AUDIENCE: "a Word document",
85
+ "pptx-studio": "a presentation",
86
+ "xlsx-studio": "a spreadsheet",
87
+ }
88
+
89
+
90
+ def public_api_base(url: str) -> str:
91
+ """The public API base for ``url``, whether or not it already ends in it."""
92
+ base = url.strip().rstrip("/")
93
+ if base.endswith(PUBLIC_API_PREFIX):
94
+ return base
95
+ return base + PUBLIC_API_PREFIX
96
+
97
+
98
+ @dataclass(frozen=True)
99
+ class StudioToken:
100
+ """One minted token and what Athena said about it."""
101
+
102
+ token: str = field(repr=False)
103
+ asset_id: str
104
+ audience: str
105
+ #: ``"r"`` (reads only) or ``"rw"``.
106
+ access_type: str
107
+ #: ``time.monotonic()`` after which the token is minted again.
108
+ refresh_at: float
109
+
110
+ def is_fresh(self) -> bool:
111
+ return time.monotonic() < self.refresh_at
112
+
113
+
114
+ class SigningUnavailable(Exception):
115
+ """Athena's 503: this deployment signs no asset tokens."""
116
+
117
+
118
+ class MintRouteMissing(Exception):
119
+ """A 404 with FastAPI's bare route-not-found body: the Athena at
120
+ ``ATHENA_API_URL`` predates the studio-token route (a self-hosted release
121
+ older than the SDK). The client then sends ``ATHENA_API_KEY``, as before."""
122
+
123
+
124
+ #: What FastAPI answers for a path no route matches. Athena's own 404 from the
125
+ #: studio-token route names the asset ("Asset not found."), so the two never mix.
126
+ _ROUTE_NOT_FOUND_BODY = {"detail": "Not Found"}
127
+
128
+
129
+ def _is_route_missing(response: requests.Response) -> bool:
130
+ if response.status_code != 404:
131
+ return False
132
+ try:
133
+ return bool(response.json() == _ROUTE_NOT_FOUND_BODY)
134
+ except ValueError:
135
+ return False
136
+
137
+
138
+ class _TokenCache:
139
+ """Process-wide tokens by (agora, key, asset, access), least recently used first."""
140
+
141
+ def __init__(self, max_entries: int) -> None:
142
+ self._entries: OrderedDict[tuple[str, str, str, str], StudioToken] = OrderedDict()
143
+ self._max_entries = max_entries
144
+ self._lock = threading.Lock()
145
+ # Minting holds one stripe, so threads wanting the same token wait for
146
+ # one mint instead of each minting their own.
147
+ self._mint_locks = tuple(threading.Lock() for _ in range(_LOCK_STRIPES))
148
+
149
+ def get(self, key: tuple[str, str, str, str]) -> StudioToken | None:
150
+ with self._lock:
151
+ token = self._entries.get(key)
152
+ if token is not None:
153
+ self._entries.move_to_end(key)
154
+ return token
155
+
156
+ def put(self, key: tuple[str, str, str, str], token: StudioToken) -> None:
157
+ with self._lock:
158
+ self._entries[key] = token
159
+ self._entries.move_to_end(key)
160
+ while len(self._entries) > self._max_entries:
161
+ self._entries.popitem(last=False)
162
+
163
+ def discard(self, key: tuple[str, str, str, str], token: StudioToken) -> None:
164
+ """Forget ``token`` unless another thread already replaced it."""
165
+ with self._lock:
166
+ if self._entries.get(key) is token:
167
+ del self._entries[key]
168
+
169
+ def mint_lock(self, key: tuple[str, str, str, str]) -> threading.Lock:
170
+ return self._mint_locks[hash(key) % _LOCK_STRIPES]
171
+
172
+ def clear(self) -> None:
173
+ with self._lock:
174
+ self._entries.clear()
175
+
176
+
177
+ _CACHE = _TokenCache(_MAX_CACHED_TOKENS)
178
+
179
+ _SESSION: requests.Session | None = None
180
+ _SESSION_LOCK = threading.Lock()
181
+
182
+
183
+ def _mint_session() -> requests.Session:
184
+ """One session for every mint: connection retries, and status retries for
185
+ 429/502/504. A 503 is Athena's answer, not a transient fault, so it is not
186
+ retried; minting is safe to resend (each mint only signs a new token)."""
187
+ global _SESSION
188
+ with _SESSION_LOCK:
189
+ if _SESSION is None:
190
+ retry_kwargs: dict[str, Any] = {
191
+ "total": None,
192
+ "status": 2,
193
+ "connect": 2,
194
+ "read": 0,
195
+ "other": 0,
196
+ "backoff_factor": 0.5,
197
+ "status_forcelist": (429, 502, 504),
198
+ "allowed_methods": frozenset(["POST"]),
199
+ "raise_on_status": False,
200
+ "respect_retry_after_header": True,
201
+ }
202
+ if "backoff_max" in inspect.signature(Retry).parameters:
203
+ retry_kwargs["backoff_max"] = 5.0
204
+ session = requests.Session()
205
+ adapter = HTTPAdapter(max_retries=Retry(**retry_kwargs))
206
+ session.mount("http://", adapter)
207
+ session.mount("https://", adapter)
208
+ _SESSION = session
209
+ return _SESSION
210
+
211
+
212
+ def _detail(response: requests.Response) -> str:
213
+ """Athena's reason (``{"detail": ...}``), else a short excerpt of the body."""
214
+ try:
215
+ body = response.json()
216
+ except ValueError:
217
+ return " ".join((response.text or "").split())[:200]
218
+ detail = body.get("detail") if isinstance(body, dict) else None
219
+ if isinstance(detail, dict):
220
+ detail = detail.get("message")
221
+ if isinstance(detail, str):
222
+ return detail.strip()
223
+ return ""
224
+
225
+
226
+ def _lifetime_seconds(expires_at_ms: int) -> float:
227
+ """How long to hold a token, from Athena's expiry and the local clock."""
228
+ remaining = expires_at_ms / 1000.0 - time.time()
229
+ return min(max(remaining, MIN_LIFETIME_SECONDS), MAX_LIFETIME_SECONDS)
230
+
231
+
232
+ class TokenMinter:
233
+ """Mints the studio tokens one ``ATHENA_API_KEY`` holds, through the cache."""
234
+
235
+ def __init__(self, *, api_url: str, api_key: str) -> None:
236
+ self.base = public_api_base(api_url)
237
+ self._api_key = api_key
238
+ self._fingerprint = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
239
+
240
+ @classmethod
241
+ def from_environment(cls) -> TokenMinter | None:
242
+ """The minter for ``ATHENA_API_KEY`` at ``ATHENA_API_URL``; None when either is unset."""
243
+ api_key = os.environ.get(API_KEY_ENV)
244
+ api_url = os.environ.get(API_URL_ENV)
245
+ if not api_key or not api_url or not api_url.strip():
246
+ return None
247
+ return cls(api_url=api_url, api_key=api_key)
248
+
249
+ def _key(self, *, asset_id: str, access: str) -> tuple[str, str, str, str]:
250
+ return (self.base, self._fingerprint, asset_id, access)
251
+
252
+ def token(self, *, asset_id: str, access: str) -> StudioToken:
253
+ """The token for ``asset_id`` at ``access``: the cached one while fresh,
254
+ else a new one. Raises when Athena refuses it, when it is for another
255
+ studio, and :class:`SigningUnavailable` on a 503."""
256
+ key = self._key(asset_id=asset_id, access=access)
257
+ token = _CACHE.get(key)
258
+ if token is None or not token.is_fresh():
259
+ with _CACHE.mint_lock(key):
260
+ token = _CACHE.get(key)
261
+ if token is None or not token.is_fresh():
262
+ token = self._mint(asset_id=asset_id, access=access)
263
+ _CACHE.put(key, token)
264
+ if token.audience != AUDIENCE:
265
+ raise DocxError(
266
+ f"Asset {asset_id} is not a Word document: Athena edits it through "
267
+ f"{token.audience}. Open it with the Athena SDK for "
268
+ f"{_KIND_BY_AUDIENCE.get(token.audience, 'that kind of asset')}."
269
+ )
270
+ return token
271
+
272
+ def invalidate(self, *, token: StudioToken, access: str) -> None:
273
+ """Forget ``token`` (the studio answered 401 to it), so the next call mints."""
274
+ _CACHE.discard(self._key(asset_id=token.asset_id, access=access), token)
275
+
276
+ def _mint(self, *, asset_id: str, access: str) -> StudioToken:
277
+ url = f"{self.base}/assets/{quote(asset_id, safe='')}/studio-token"
278
+ try:
279
+ response = _mint_session().post(
280
+ url,
281
+ json={"access": access},
282
+ headers={"X-API-KEY": self._api_key, "Accept": "application/json"},
283
+ timeout=MINT_TIMEOUT_SECONDS,
284
+ )
285
+ except requests.RequestException as exc:
286
+ raise SessionError(
287
+ f"Unable to reach Athena at {url} to mint a DOCX Studio token for "
288
+ f"{asset_id}: {exc}"
289
+ ) from exc
290
+ try:
291
+ return self._read(response, asset_id=asset_id)
292
+ finally:
293
+ response.close()
294
+
295
+ @staticmethod
296
+ def _read(response: requests.Response, *, asset_id: str) -> StudioToken:
297
+ status = response.status_code
298
+ if status == 503:
299
+ raise SigningUnavailable(_detail(response) or "This deployment signs no asset tokens.")
300
+ if _is_route_missing(response):
301
+ raise MintRouteMissing(f"no studio-token route at {response.url}")
302
+ detail = _detail(response)
303
+ reason = f"(HTTP {status}{': ' + detail if detail else ''})"
304
+ if status == 401:
305
+ raise AuthenticationError(
306
+ f"Athena refused ATHENA_API_KEY when asked for a DOCX Studio token for "
307
+ f"{asset_id} {reason}. The key is invalid, expired or revoked; retrying "
308
+ "with it will not help."
309
+ )
310
+ if status == 403:
311
+ raise AuthenticationError(f"Athena refused a DOCX Studio token for {asset_id} {reason}.")
312
+ if status == 404:
313
+ raise NotFoundError(
314
+ f"Athena refused a DOCX Studio token for {asset_id} {reason}: the document "
315
+ "does not exist, or this key may not read it.",
316
+ payload={"status": 404, "body": detail},
317
+ )
318
+ if status in (400, 422):
319
+ raise DocxError(f"Athena refused a DOCX Studio token for {asset_id} {reason}.")
320
+ if not response.ok:
321
+ raise DocxStudioTemporarilyUnavailable(
322
+ f"Athena could not mint a DOCX Studio token for {asset_id} {reason}.",
323
+ http_status=status,
324
+ )
325
+ try:
326
+ body = response.json()
327
+ except ValueError:
328
+ body = None
329
+ if not isinstance(body, dict):
330
+ body = {}
331
+ token = body.get("token")
332
+ audience = body.get("audience")
333
+ access_type = body.get("access_type")
334
+ expires_at_ms = body.get("expires_at_ms")
335
+ if (
336
+ not isinstance(token, str)
337
+ or not token.startswith(TOKEN_PREFIX)
338
+ or not isinstance(audience, str)
339
+ or access_type not in ("r", "rw")
340
+ or not isinstance(expires_at_ms, int)
341
+ or isinstance(expires_at_ms, bool)
342
+ or body.get("asset_id") != asset_id
343
+ ):
344
+ raise SessionError(
345
+ f"Athena's studio token answer for {asset_id} is not one this SDK can use "
346
+ "(expected token, audience, access_type, expires_at_ms and this asset id)."
347
+ )
348
+ return StudioToken(
349
+ token=token,
350
+ asset_id=asset_id,
351
+ audience=audience,
352
+ access_type=access_type,
353
+ refresh_at=time.monotonic()
354
+ + max(
355
+ _lifetime_seconds(expires_at_ms) - REFRESH_BEFORE_EXPIRY_SECONDS,
356
+ MIN_LIFETIME_SECONDS,
357
+ ),
358
+ )
359
+
360
+
361
+ def studio_credentials(*, api_key: str | None) -> tuple[str | None, TokenMinter | None]:
362
+ """What a client authenticates with: ``(key, minter)``.
363
+
364
+ ``key`` serves every route the minter does not: ``api_key`` when the caller
365
+ passed one, else ``ATHENA_DOCX_API_KEY``, else ``ATHENA_API_KEY``. ``minter``
366
+ mints per-document tokens when neither of the first two is set and
367
+ ``ATHENA_API_KEY`` and ``ATHENA_API_URL`` are.
368
+ """
369
+ if api_key:
370
+ return api_key, None
371
+ studio_key = os.environ.get(STUDIO_KEY_ENV)
372
+ if studio_key:
373
+ return studio_key, None
374
+ return os.environ.get(API_KEY_ENV), TokenMinter.from_environment()
375
+
376
+
377
+ def _clear_cache() -> None:
378
+ """Forget every cached token (tests)."""
379
+ _CACHE.clear()
@@ -45,8 +45,10 @@ def _resolve_api_key(api_key: str | None) -> str | None:
45
45
  makes. Both create paths land outside Athena's public API (docx-studio's
46
46
  ``/docs/empty``, agora's ``/api/docx-studio/assets``), and inside an Athena
47
47
  session VM or computer ``ATHENA_API_KEY`` is a credential only that public
48
- API (``/api/v0``) accepts. ``ATHENA_API_KEY`` stays the fallback for an
49
- environment that sets no studio key (local use with one personal key).
48
+ API (``/api/v0``) accepts: there (neither key set, ``ATHENA_API_URL`` set)
49
+ Athena's public API creates the document instead (``docx._public_create``).
50
+ ``ATHENA_API_KEY`` stays the fallback for an environment that sets no
51
+ studio key and no ``ATHENA_API_URL`` (local use with one personal key).
50
52
  The new document is owned by the user the key belongs to.
51
53
  """
52
54
  return api_key or os.environ.get(_API_KEY_ENV) or os.environ.get("ATHENA_API_KEY")
@@ -137,6 +139,14 @@ def create_empty_document(
137
139
  "Pass base_url= to Document.create() or set the env var "
138
140
  '(e.g. ATHENA_DOCX_BASE_URL="https://docx-studio.prd.athenaintel.com").',
139
141
  )
142
+ created = _create_through_athena(
143
+ api_key=api_key,
144
+ name=name,
145
+ parent_folder_id=parent_folder_id,
146
+ workspace_id=workspace_id,
147
+ )
148
+ if created is not None:
149
+ return created
140
150
  if not resolved_key:
141
151
  raise AuthenticationError(
142
152
  f"Missing api_key and {_API_KEY_ENV} env var. "
@@ -221,6 +231,44 @@ def create_empty_document(
221
231
  )
222
232
 
223
233
 
234
+ def _create_through_athena(
235
+ *,
236
+ api_key: str | None,
237
+ name: str | None,
238
+ parent_folder_id: str | None,
239
+ workspace_id: str | None,
240
+ ) -> CreateAssetResult | None:
241
+ """A new document Athena's public API made, or None for docx-studio's path.
242
+
243
+ Athena creates it when no ``api_key`` and no ``ATHENA_DOCX_API_KEY`` are set
244
+ and ``ATHENA_API_KEY`` and ``ATHENA_API_URL`` are (``docx._public_create``).
245
+ None otherwise, and when that Athena predates the public create.
246
+ """
247
+ from docx._public_create import (
248
+ PublicApi,
249
+ PublicCreateUnavailable,
250
+ create_word_document,
251
+ )
252
+
253
+ api = PublicApi.for_creation(api_key=api_key)
254
+ if api is None:
255
+ return None
256
+ try:
257
+ created = create_word_document(
258
+ api=api,
259
+ name=name,
260
+ parent_folder_id=parent_folder_id,
261
+ workspace_id=workspace_id or os.environ.get("ATHENA_WORKSPACE_ID"),
262
+ )
263
+ except PublicCreateUnavailable:
264
+ return None
265
+ return CreateAssetResult(
266
+ asset_id=created["asset_id"],
267
+ name=created["title"],
268
+ workspace_id=created["workspace_id"] or "",
269
+ )
270
+
271
+
224
272
  class UploadAssetResult(TypedDict):
225
273
  """Parsed response from the create-and-import upload flow."""
226
274
 
@@ -228,6 +276,58 @@ class UploadAssetResult(TypedDict):
228
276
  name: str
229
277
 
230
278
 
279
+ def _upload_through_athena(
280
+ *,
281
+ docx_path: str,
282
+ api_key: str | None,
283
+ name: str | None,
284
+ parent_folder_id: str | None,
285
+ workspace_id: str | None,
286
+ source_asset_id: str | None,
287
+ timeout: float,
288
+ ) -> UploadAssetResult | None:
289
+ """A document Athena made from the ``.docx`` at ``docx_path``, or None.
290
+
291
+ Athena's ``POST /api/v0/assets/create-from-file`` makes it in one request
292
+ when no ``api_key`` and no ``ATHENA_DOCX_API_KEY`` are set and
293
+ ``ATHENA_API_KEY`` and ``ATHENA_API_URL`` are (``docx._public_create``).
294
+ None otherwise, and when that Athena predates the route: the upload then
295
+ goes through agora's docx-studio bridge, as before.
296
+ """
297
+ from docx._public_create import (
298
+ PublicApi,
299
+ PublicCreateUnavailable,
300
+ create_word_document_from_file,
301
+ )
302
+
303
+ api = PublicApi.for_creation(api_key=api_key)
304
+ if api is None:
305
+ return None
306
+ if not os.path.exists(docx_path):
307
+ raise SessionError(f"DOCX file not found: {docx_path}")
308
+ if not docx_path.lower().endswith(".docx"):
309
+ raise SessionError(
310
+ f"Only .docx files are accepted by the upload endpoint (got {docx_path})",
311
+ )
312
+ title = name
313
+ if title is None:
314
+ base = os.path.basename(docx_path)
315
+ title = base[:-5] if base.lower().endswith(".docx") else base
316
+ try:
317
+ created = create_word_document_from_file(
318
+ api=api,
319
+ docx_path=docx_path,
320
+ title=title,
321
+ parent_folder_id=parent_folder_id,
322
+ workspace_id=workspace_id or os.environ.get("ATHENA_WORKSPACE_ID"),
323
+ source_asset_id=source_asset_id,
324
+ timeout=timeout,
325
+ )
326
+ except PublicCreateUnavailable:
327
+ return None
328
+ return UploadAssetResult(asset_id=created["asset_id"], name=created["title"])
329
+
330
+
231
331
  def upload_document(
232
332
  *,
233
333
  docx_path: str,
@@ -273,6 +373,18 @@ def upload_document(
273
373
  import base64
274
374
  import os
275
375
 
376
+ uploaded = _upload_through_athena(
377
+ docx_path=docx_path,
378
+ api_key=api_key,
379
+ name=name,
380
+ parent_folder_id=parent_folder_id,
381
+ workspace_id=workspace_id,
382
+ source_asset_id=source_asset_id,
383
+ timeout=timeout,
384
+ )
385
+ if uploaded is not None:
386
+ return uploaded
387
+
276
388
  resolved_docx_base: str | None = docx_base_url or os.environ.get(_BASE_URL_ENV)
277
389
  resolved_key: str | None = _resolve_api_key(api_key)
278
390
  resolved_agora_base: str | None = (