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