athena-python-docx 0.44.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.44.0 → athena_python_docx-0.45.0}/PKG-INFO +1 -1
  2. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/__init__.py +1 -1
  3. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_asset_token.py +28 -3
  4. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_http.py +114 -2
  5. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_http_doc.py +6 -1
  6. athena_python_docx-0.45.0/docx/_public_create.py +270 -0
  7. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/document.py +5 -1
  8. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/pyproject.toml +1 -1
  9. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_asset_tokens.py +39 -24
  10. athena_python_docx-0.45.0/tests/test_public_create.py +473 -0
  11. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/uv.lock +1 -1
  12. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/.gitignore +0 -0
  13. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/AGENTS.md +0 -0
  14. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/CLAUDE.md +0 -0
  15. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/DOCX_EXEC_LAB.md +0 -0
  16. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/README.md +0 -0
  17. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_athena_extension.py +0 -0
  18. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_batching.py +0 -0
  19. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_buffer.py +0 -0
  20. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_capabilities.py +0 -0
  21. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_citations.py +0 -0
  22. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_execution.py +0 -0
  23. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_image_utils.py +0 -0
  24. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_postproc.py +0 -0
  25. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_proxy.py +0 -0
  26. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_ptc.py +0 -0
  27. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_references.py +0 -0
  28. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_run_order.py +0 -0
  29. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_table_styles.py +0 -0
  30. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_timeouts.py +0 -0
  31. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_tracked.py +0 -0
  32. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/_xml_text.py +0 -0
  33. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/api.py +0 -0
  34. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/blkcntnr.py +0 -0
  35. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/bookmarks.py +0 -0
  36. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/charts.py +0 -0
  37. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/client.py +0 -0
  38. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/commands.py +0 -0
  39. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/comments.py +0 -0
  40. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/drawing/__init__.py +0 -0
  41. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/__init__.py +0 -0
  42. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/base.py +0 -0
  43. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/dml.py +0 -0
  44. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/section.py +0 -0
  45. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/shape.py +0 -0
  46. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/style.py +0 -0
  47. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/table.py +0 -0
  48. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/enum/text.py +0 -0
  49. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/errors.py +0 -0
  50. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/exceptions.py +0 -0
  51. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/fields.py +0 -0
  52. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/footnotes.py +0 -0
  53. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/image/__init__.py +0 -0
  54. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/image/exceptions.py +0 -0
  55. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/image/image.py +0 -0
  56. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/math.py +0 -0
  57. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/opc/__init__.py +0 -0
  58. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/opc/coreprops.py +0 -0
  59. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/oxml/__init__.py +0 -0
  60. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/revisions.py +0 -0
  61. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/sdt.py +0 -0
  62. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/section.py +0 -0
  63. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/session.py +0 -0
  64. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/settings.py +0 -0
  65. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/shape.py +0 -0
  66. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/shared.py +0 -0
  67. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/styles/__init__.py +0 -0
  68. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/styles/_table.py +0 -0
  69. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/styles/latent.py +0 -0
  70. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/styles/style.py +0 -0
  71. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/styles/styles.py +0 -0
  72. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/table.py +0 -0
  73. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/__init__.py +0 -0
  74. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/font.py +0 -0
  75. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/hyperlink.py +0 -0
  76. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/pagebreak.py +0 -0
  77. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/paragraph.py +0 -0
  78. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/parfmt.py +0 -0
  79. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/run.py +0 -0
  80. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/text/tabstops.py +0 -0
  81. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/toc.py +0 -0
  82. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/docx/typing.py +0 -0
  83. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab.py +0 -0
  84. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
  85. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
  86. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/docx_exec_lab_server.py +0 -0
  87. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/dump_wire_fixtures.py +0 -0
  88. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/release.sh +0 -0
  89. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/round_trip_smoke.py +0 -0
  90. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/smoke_test_block_not_found.py +0 -0
  91. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/scripts/validate_find_replace_asset.py +0 -0
  92. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/__init__.py +0 -0
  93. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/conftest.py +0 -0
  94. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/METHODOLOGY.md +0 -0
  95. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/README.md +0 -0
  96. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/__init__.py +0 -0
  97. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/__init__.py +0 -0
  98. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/agent_documents.py +0 -0
  99. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
  100. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
  101. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
  102. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
  103. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
  104. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/picture_runs.py +0 -0
  105. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
  106. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/return_types.py +0 -0
  107. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
  108. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
  109. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe_cases.py +0 -0
  110. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ab_probe_runner.py +0 -0
  111. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/auto_gen_cases.py +0 -0
  112. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/binary_round_trip.py +0 -0
  113. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/cases.py +0 -0
  114. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/complex_cases.py +0 -0
  115. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/coverage_report.py +0 -0
  116. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/extract.py +0 -0
  117. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/extreme_cases.py +0 -0
  118. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/fake_session.py +0 -0
  119. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/README.md +0 -0
  120. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/__init__.py +0 -0
  121. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/_runner.py +0 -0
  122. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/extractor.py +0 -0
  123. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
  124. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
  125. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/local_runner.py +0 -0
  126. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/mega_cases.py +0 -0
  127. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshot.py +0 -0
  128. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
  129. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
  130. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
  131. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
  132. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
  133. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
  134. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
  135. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
  136. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
  137. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
  138. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
  139. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
  141. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
  142. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
  143. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
  144. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
  145. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
  146. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
  147. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
  148. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
  150. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
  152. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
  153. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
  154. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
  155. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
  156. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
  157. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
  158. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
  159. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
  160. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
  161. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
  162. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
  163. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
  164. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
  165. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
  166. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
  168. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
  169. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
  170. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
  172. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
  173. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
  174. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
  175. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
  176. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
  177. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
  178. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
  179. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
  181. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
  182. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
  183. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
  184. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
  185. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
  186. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
  187. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
  188. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
  189. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
  191. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
  192. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
  193. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
  194. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
  195. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
  196. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
  197. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
  198. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
  199. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
  200. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
  201. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
  202. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
  203. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
  204. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
  205. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
  206. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
  207. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
  209. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
  210. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
  211. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
  212. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
  214. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
  216. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
  217. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
  218. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
  220. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
  221. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
  222. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
  223. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
  224. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
  225. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
  227. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
  228. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
  229. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
  230. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
  231. {athena_python_docx-0.44.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.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
  233. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
  234. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
  235. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
  236. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
  237. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
  238. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
  239. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
  240. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
  241. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
  242. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
  243. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
  244. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
  245. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
  246. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
  247. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
  248. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
  249. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
  250. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
  251. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
  252. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
  253. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
  254. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
  255. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
  256. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
  257. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
  258. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
  259. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
  260. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
  261. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
  262. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
  263. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
  264. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
  265. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
  266. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
  267. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
  268. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
  269. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
  270. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
  271. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
  272. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
  273. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
  274. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
  275. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
  276. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
  277. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
  278. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
  279. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
  280. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/ours_spec.json +0 -0
  281. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/parity_crawl.py +0 -0
  282. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/parity_diff.json +0 -0
  283. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/real_world_cases.py +0 -0
  284. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/round_trip_tests.py +0 -0
  285. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/stock_spec.json +0 -0
  286. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
  287. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fixtures/field_reads.json +0 -0
  288. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fixtures/note_reference_reads.json +0 -0
  289. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fixtures/ruby_reads.json +0 -0
  290. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/fixtures/symbol_reads.json +0 -0
  291. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/__init__.py +0 -0
  292. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/baseline.json +0 -0
  293. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/fixture_scripts.py +0 -0
  294. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/reader.py +0 -0
  295. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/runner.py +0 -0
  296. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/sdk_driver.py +0 -0
  297. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/stock_driver.py +0 -0
  298. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/live/test_live_runner.py +0 -0
  299. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/README.md +0 -0
  300. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/__init__.py +0 -0
  301. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/baseline_gaps.json +0 -0
  302. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/compare.py +0 -0
  303. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/intentional_deviations.json +0 -0
  304. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/introspect.py +0 -0
  305. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
  306. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/reports/gap_report.json +0 -0
  307. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/run_parity.py +0 -0
  308. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/snapshots/athena_latest.json +0 -0
  309. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
  310. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/parity/test_parity_gap.py +0 -0
  311. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_add_section.py +0 -0
  312. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_add_section_extract_items.py +0 -0
  313. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_alignment_values.py +0 -0
  314. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_athena_extension_creates_session_open.py +0 -0
  315. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_athena_extensions_contract.py +0 -0
  316. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_athena_extensions_registry.py +0 -0
  317. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_batch_chunking.py +0 -0
  318. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_batching_perf.py +0 -0
  319. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_battery_cases.py +0 -0
  320. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_block_not_found_error.py +0 -0
  321. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_buffer.py +0 -0
  322. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
  323. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_add_table_not_supported.py +0 -0
  324. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_borders_spec.py +0 -0
  325. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_fastpath_runs.py +0 -0
  326. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
  327. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
  328. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_format_stash.py +0 -0
  329. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_run_format_stash.py +0 -0
  330. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_inner_run_guard.py +0 -0
  331. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_merge.py +0 -0
  332. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_nested_tables.py +0 -0
  333. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_paragraphs_listed.py +0 -0
  334. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_text_plain_fastpath.py +0 -0
  335. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_cell_text_replace_semantics.py +0 -0
  336. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_citations.py +0 -0
  337. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_collapsed_range_format.py +0 -0
  338. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_color_format_theme.py +0 -0
  339. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_command_dataclasses.py +0 -0
  340. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_commands.py +0 -0
  341. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_comment_paragraphs.py +0 -0
  342. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_comments.py +0 -0
  343. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_comments_first_read.py +0 -0
  344. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_content_control_value.py +0 -0
  345. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_core_properties.py +0 -0
  346. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_create_workspace.py +0 -0
  347. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_asset_id_property.py +0 -0
  348. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_clear.py +0 -0
  349. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_create.py +0 -0
  350. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_create_from_template.py +0 -0
  351. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_factory_validation.py +0 -0
  352. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_document_settings_session_open.py +0 -0
  353. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_docx_exec_lab.py +0 -0
  354. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_docx_exec_lab_server.py +0 -0
  355. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_drawing_image.py +0 -0
  356. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
  357. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_empty_hyperlinks.py +0 -0
  358. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_enum_parity.py +0 -0
  359. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_execution_scope.py +0 -0
  360. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_export_docx_clean.py +0 -0
  361. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_export_rescue_anchors.py +0 -0
  362. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_field_reads_python_docx_parity.py +0 -0
  363. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_field_refresh.py +0 -0
  364. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_field_runs.py +0 -0
  365. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_find_replace_session_open.py +0 -0
  366. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_flushed_write_failures.py +0 -0
  367. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_http_transport.py +0 -0
  368. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_hyperlink_coalescing.py +0 -0
  369. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_image_url_data_uri.py +0 -0
  370. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_inline_page_break.py +0 -0
  371. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_alt_text.py +0 -0
  372. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_size.py +0 -0
  373. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_inline_shape_type.py +0 -0
  374. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_inline_shapes_floating.py +0 -0
  375. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_insert_deferred.py +0 -0
  376. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_iter_inner_content.py +0 -0
  377. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_latent_style_writes.py +0 -0
  378. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_line_clear_break.py +0 -0
  379. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_list_styles.py +0 -0
  380. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_listed_paragraph_reads.py +0 -0
  381. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_literal_no_break_hyphens.py +0 -0
  382. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_literal_soft_hyphens.py +0 -0
  383. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_merged_cell_identity.py +0 -0
  384. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_merged_cell_secondary_slot.py +0 -0
  385. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_merged_cells.py +0 -0
  386. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_missing_modules.py +0 -0
  387. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_nested_table_refused.py +0 -0
  388. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
  389. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_oxml_shim.py +0 -0
  390. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_page_break.py +0 -0
  391. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_paragraph_delete.py +0 -0
  392. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_paragraph_indent_reads.py +0 -0
  393. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
  394. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_paragraph_text_empty_run.py +0 -0
  395. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_paragraph_text_len_cache.py +0 -0
  396. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_parfmt_clears.py +0 -0
  397. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_parity_misc.py +0 -0
  398. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_parity_round2.py +0 -0
  399. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_partial_failure_cascade.py +0 -0
  400. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_pdf_export_and_page_renders.py +0 -0
  401. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_phase_a_behavior.py +0 -0
  402. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_phase_b_headers_footers.py +0 -0
  403. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_phase_c_tables.py +0 -0
  404. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_positional_cell_id.py +0 -0
  405. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
  406. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
  407. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_postproc_ref_restore.py +0 -0
  408. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_pr19766_review_fixes.py +0 -0
  409. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_proxy_equality.py +0 -0
  410. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_ptc.py +0 -0
  411. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_python_docx_api_parity.py +0 -0
  412. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_read_run_ranges.py +0 -0
  413. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_rendered_page_breaks.py +0 -0
  414. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_repeated_node_read.py +0 -0
  415. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_restart_numbering.py +0 -0
  416. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_revisions.py +0 -0
  417. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_round_trip_smoke_script.py +0 -0
  418. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
  419. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_add_picture_anchor.py +0 -0
  420. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_break_inner_content.py +0 -0
  421. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_edges.py +0 -0
  422. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_formatting_wire.py +0 -0
  423. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_identity.py +0 -0
  424. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_later_runs.py +0 -0
  425. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_mark_inheritance.py +0 -0
  426. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_page_number_blocks.py +0 -0
  427. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_table_style_objects.py +0 -0
  428. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_text_python_docx.py +0 -0
  429. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
  430. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_run_unmodeled_toggles.py +0 -0
  431. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_sdk_reads_served.py +0 -0
  432. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_section_read_lengths.py +0 -0
  433. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_sections_empty_list.py +0 -0
  434. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
  435. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_picture.py +0 -0
  436. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_add_run.py +0 -0
  437. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
  438. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
  439. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_comments_get.py +0 -0
  440. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_document_audit.py +0 -0
  441. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_document_element.py +0 -0
  442. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_enum_section.py +0 -0
  443. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_font_audit.py +0 -0
  444. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_header_footer.py +0 -0
  445. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_hyperlink.py +0 -0
  446. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_inline_shape.py +0 -0
  447. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
  448. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_misc.py +0 -0
  449. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
  450. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_style.py +0 -0
  451. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
  452. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_parfmt.py +0 -0
  453. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_row_col_cell.py +0 -0
  454. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_add_break.py +0 -0
  455. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
  456. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_style.py +0 -0
  457. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_style_strict.py +0 -0
  458. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_text.py +0 -0
  459. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_run_underline.py +0 -0
  460. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_audit.py +0 -0
  461. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_dimensions.py +0 -0
  462. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_section_onoff.py +0 -0
  463. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_settings.py +0 -0
  464. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_shared_audit.py +0 -0
  465. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_style.py +0 -0
  466. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_styles.py +0 -0
  467. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_audit.py +0 -0
  468. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_cell.py +0 -0
  469. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_dimensions.py +0 -0
  470. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_silent_stub_table_layout.py +0 -0
  471. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_smoke_integration.py +0 -0
  472. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_acceptance.py +0 -0
  473. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_delete.py +0 -0
  474. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_font.py +0 -0
  475. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_formatting_writes.py +0 -0
  476. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_metadata_writes.py +0 -0
  477. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_names.py +0 -0
  478. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_resolution.py +0 -0
  479. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_setters_contract.py +0 -0
  480. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_tab_stops.py +0 -0
  481. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_style_tab_stops_read.py +0 -0
  482. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
  483. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_tab_stop_writes.py +0 -0
  484. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_add_row_grid_row.py +0 -0
  485. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_anchors.py +0 -0
  486. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_clears.py +0 -0
  487. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_direction.py +0 -0
  488. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_length_reads.py +0 -0
  489. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_listing_reads.py +0 -0
  490. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_read_reuse.py +0 -0
  491. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_set_cell_perf.py +0 -0
  492. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_table_style_id_resolution.py +0 -0
  493. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_temporarily_unavailable.py +0 -0
  494. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_text_control_characters.py +0 -0
  495. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_tracked_revisions_offsets.py +0 -0
  496. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_unmapped_alignment_reads.py +0 -0
  497. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_uv_lock_version.py +0 -0
  498. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_validate_find_replace_asset_script.py +0 -0
  499. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_versioned_read_reuse.py +0 -0
  500. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_wire_contract.py +0 -0
  501. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_xml_attr_guard.py +0 -0
  502. {athena_python_docx-0.44.0 → athena_python_docx-0.45.0}/tests/test_xml_incompatible_text.py +0 -0
  503. {athena_python_docx-0.44.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.44.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>
@@ -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.44.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
@@ -13,8 +13,9 @@ A call on an existing Word document reaches DOCX Studio with, in this order:
13
13
  4. otherwise ``ATHENA_API_KEY`` itself, as before.
14
14
 
15
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.
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.
18
19
 
19
20
  A token is minted once per (agora, key, asset, access) for the whole process,
20
21
  again 90 seconds before it expires, and once more when the studio answers 401.
@@ -28,7 +29,9 @@ or locally; both work.
28
29
 
29
30
  Athena's refusals (400, 401, 403, 404, 422) raise at once, without a retry. A
30
31
  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
+ 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.
32
35
  """
33
36
 
34
37
  from __future__ import annotations
@@ -112,6 +115,26 @@ class SigningUnavailable(Exception):
112
115
  """Athena's 503: this deployment signs no asset tokens."""
113
116
 
114
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
+
115
138
  class _TokenCache:
116
139
  """Process-wide tokens by (agora, key, asset, access), least recently used first."""
117
140
 
@@ -274,6 +297,8 @@ class TokenMinter:
274
297
  status = response.status_code
275
298
  if status == 503:
276
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}")
277
302
  detail = _detail(response)
278
303
  reason = f"(HTTP {status}{': ' + detail if detail else ''})"
279
304
  if status == 401:
@@ -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 = (
@@ -47,6 +47,7 @@ from docx._asset_token import (
47
47
  EDIT,
48
48
  STUDIO_KEY_ENV,
49
49
  VIEW,
50
+ MintRouteMissing,
50
51
  SigningUnavailable,
51
52
  StudioToken,
52
53
  TokenMinter,
@@ -1127,6 +1128,10 @@ class HttpClient:
1127
1128
  token = minter.token(asset_id=asset_id, access=access)
1128
1129
  except SigningUnavailable as exc:
1129
1130
  return self._without_asset_tokens(asset_id=asset_id, reason=str(exc)), None
1131
+ except MintRouteMissing:
1132
+ # The Athena at ATHENA_API_URL predates the route: the key, as before.
1133
+ self._asset_tokens = None
1134
+ return self._api_key, None
1130
1135
  return token.token, (token, access)
1131
1136
 
1132
1137
  def _without_asset_tokens(self, *, asset_id: str, reason: str) -> str:
@@ -1160,7 +1165,7 @@ class HttpClient:
1160
1165
  minter.invalidate(token=refused, access=granted_access)
1161
1166
  try:
1162
1167
  fresh = minter.token(asset_id=asset_id, access=granted_access)
1163
- except SigningUnavailable:
1168
+ except (SigningUnavailable, MintRouteMissing):
1164
1169
  raise exc from None
1165
1170
  if fresh.token == refused.token:
1166
1171
  raise
@@ -0,0 +1,270 @@
1
+ """Creating a Word document through Athena's public API when no studio key is set.
2
+
3
+ ``Document.create()`` creates a document with the key every other call sends
4
+ (``api_key``, ``ATHENA_DOCX_API_KEY``, then ``ATHENA_API_KEY``), except when
5
+ neither of the first two is set and ``ATHENA_API_KEY`` and ``ATHENA_API_URL``
6
+ both are. That is a computer's or a session VM's scoped credential, which
7
+ Athena's public API (``/api/v0``) takes and neither docx-studio's ``/docs/empty``
8
+ nor agora's ``/api/docx-studio/assets`` does, so Athena creates the document:
9
+
10
+ * a document holding Athena's default template:
11
+ ``POST {ATHENA_API_URL}/api/v0/assets/create`` with
12
+ ``{"asset_type": "word_document", ...}``;
13
+ * a document holding a local ``.docx`` (``Document.create(docx=...)``):
14
+ ``POST {ATHENA_API_URL}/api/v0/assets/create-from-file`` (multipart ``file``,
15
+ query ``title``, ``parent_folder_id``, ``workspace_id``, ``source_asset_id``).
16
+
17
+ Both send ``X-API-KEY: $ATHENA_API_KEY`` and, inside an agent run, the run's
18
+ ``X-Athena-Session-Credential`` (``ATHENA_CLI_SESSION_KEY``), so the document's
19
+ first write records the run. Athena writes it with its own studio credential,
20
+ as the key's user, and answers once the document holds its content; its own
21
+ calls then carry a token minted for it (``docx._asset_token``).
22
+
23
+ An Athena older than these routes answers 422 naming the asset type, or
24
+ FastAPI's bare 404 or 405: the caller then creates through docx-studio and agora
25
+ with ``ATHENA_API_KEY``, as before (:class:`PublicCreateUnavailable`). Every
26
+ other refusal raises. A create is not resent once its request may have reached
27
+ Athena: a resend could make a second document.
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import inspect
33
+ import os
34
+ from dataclasses import dataclass, field
35
+ from pathlib import Path
36
+ from typing import Any, TypedDict
37
+
38
+ import requests
39
+ from requests.adapters import HTTPAdapter
40
+ from urllib3.util.retry import Retry
41
+
42
+ from docx._asset_token import API_KEY_ENV, API_URL_ENV, STUDIO_KEY_ENV, public_api_base
43
+ from docx.errors import AuthenticationError, DocxError, SessionError
44
+
45
+ #: The credential the athena CLI's session VM exports for one ``execute`` call.
46
+ SESSION_CREDENTIAL_ENV = "ATHENA_CLI_SESSION_KEY"
47
+ #: The header Athena reads it from to name the agent run a write belongs to.
48
+ SESSION_CREDENTIAL_HEADER = "X-Athena-Session-Credential"
49
+ #: Athena waits for docx-studio's seed or import before it answers.
50
+ CREATE_TIMEOUT_SECONDS = 120.0
51
+ _DOCX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
52
+ # What FastAPI answers for a path no route serves (404) or serves with other
53
+ # methods only (405: ``/assets/{asset_id}`` takes GET and PATCH).
54
+ _ROUTE_MISSING_BODIES = ({"detail": "Not Found"}, {"detail": "Method Not Allowed"})
55
+
56
+
57
+ class PublicCreateUnavailable(Exception):
58
+ """The Athena at ``ATHENA_API_URL`` predates creating a Word document through it."""
59
+
60
+
61
+ class CreatedDocument(TypedDict):
62
+ """What Athena answered: the new document's id, title and workspace."""
63
+
64
+ asset_id: str
65
+ title: str
66
+ workspace_id: str | None
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class PublicApi:
71
+ """Athena's public API, reached with ``ATHENA_API_KEY``."""
72
+
73
+ base: str
74
+ api_key: str = field(repr=False)
75
+
76
+ @classmethod
77
+ def for_creation(cls, *, api_key: str | None) -> PublicApi | None:
78
+ """The public API a new document is created through, or None.
79
+
80
+ None when the caller passed ``api_key`` or ``ATHENA_DOCX_API_KEY`` is
81
+ set (they create on docx-studio, as before), or when ``ATHENA_API_KEY``
82
+ or ``ATHENA_API_URL`` is unset.
83
+ """
84
+ if api_key or os.environ.get(STUDIO_KEY_ENV):
85
+ return None
86
+ athena_key = os.environ.get(API_KEY_ENV)
87
+ api_url = os.environ.get(API_URL_ENV)
88
+ if not athena_key or not api_url or not api_url.strip():
89
+ return None
90
+ return cls(base=public_api_base(api_url), api_key=athena_key)
91
+
92
+ def headers(self) -> dict[str, str]:
93
+ from docx import __version__
94
+
95
+ headers = {
96
+ "X-API-KEY": self.api_key,
97
+ "Accept": "application/json",
98
+ "User-Agent": f"athena-python-docx/{__version__}",
99
+ }
100
+ session_credential = os.environ.get(SESSION_CREDENTIAL_ENV)
101
+ if session_credential:
102
+ headers[SESSION_CREDENTIAL_HEADER] = session_credential
103
+ return headers
104
+
105
+
106
+ def _create_session() -> requests.Session:
107
+ """Connection retries only: a create that may have reached Athena is never resent."""
108
+ retry_kwargs: dict[str, Any] = {
109
+ "total": None,
110
+ "status": 0,
111
+ "connect": 2,
112
+ "read": 0,
113
+ "other": 0,
114
+ "backoff_factor": 0.5,
115
+ "allowed_methods": frozenset(["POST"]),
116
+ "raise_on_status": False,
117
+ }
118
+ if "backoff_max" in inspect.signature(Retry).parameters:
119
+ retry_kwargs["backoff_max"] = 5.0
120
+ session = requests.Session()
121
+ adapter = HTTPAdapter(max_retries=Retry(**retry_kwargs))
122
+ session.mount("http://", adapter)
123
+ session.mount("https://", adapter)
124
+ return session
125
+
126
+
127
+ def _json(response: requests.Response) -> Any:
128
+ try:
129
+ return response.json()
130
+ except ValueError:
131
+ return None
132
+
133
+
134
+ def _detail(body: Any, response: requests.Response) -> str:
135
+ """Athena's reason: ``detail`` as text, or the first validation message."""
136
+ detail = body.get("detail") if isinstance(body, dict) else None
137
+ if isinstance(detail, str):
138
+ return detail.strip()
139
+ if isinstance(detail, list) and detail and isinstance(detail[0], dict):
140
+ message = detail[0].get("msg")
141
+ if isinstance(message, str):
142
+ return message.strip()
143
+ return " ".join((response.text or "").split())[:200]
144
+
145
+
146
+ def _is_unavailable(*, status: int, body: Any) -> bool:
147
+ """An Athena that predates the route, or the ``word_document`` asset type."""
148
+ if status in (404, 405) and body in _ROUTE_MISSING_BODIES:
149
+ return True
150
+ if status != 422 or not isinstance(body, dict):
151
+ return False
152
+ errors = body.get("detail")
153
+ return isinstance(errors, list) and any(
154
+ isinstance(error, dict)
155
+ and "asset_type" in (error.get("loc") or [])
156
+ and "Unsupported asset type" in str(error.get("msg", ""))
157
+ for error in errors
158
+ )
159
+
160
+
161
+ def _created(response: requests.Response, *, what: str) -> CreatedDocument:
162
+ status = response.status_code
163
+ body = _json(response)
164
+ if _is_unavailable(status=status, body=body):
165
+ raise PublicCreateUnavailable(f"{response.url} answered HTTP {status}")
166
+ if status == 200 and isinstance(body, dict):
167
+ asset_id = body.get("asset_id")
168
+ title = body.get("title")
169
+ workspace_id = body.get("workspace_id")
170
+ if (
171
+ isinstance(asset_id, str)
172
+ and asset_id.startswith("asset_")
173
+ and isinstance(title, str)
174
+ and (workspace_id is None or isinstance(workspace_id, str))
175
+ ):
176
+ return CreatedDocument(asset_id=asset_id, title=title, workspace_id=workspace_id)
177
+ detail = _detail(body, response)
178
+ if status in (401, 403):
179
+ raise AuthenticationError(
180
+ f"Athena refused to create {what} with ATHENA_API_KEY (HTTP {status})"
181
+ f"{': ' + detail if detail else ''}",
182
+ )
183
+ if status == 200:
184
+ raise SessionError(f"Athena's answer to creating {what} is not one this SDK can use: {detail}")
185
+ raise DocxError(f"Athena could not create {what} (HTTP {status}){': ' + detail if detail else ''}")
186
+
187
+
188
+ def _post(
189
+ *,
190
+ session: requests.Session,
191
+ url: str,
192
+ what: str,
193
+ **kwargs: Any,
194
+ ) -> CreatedDocument:
195
+ try:
196
+ response = session.post(url, **kwargs)
197
+ except requests.RequestException as exc:
198
+ raise SessionError(f"Unable to reach Athena at {url} to create {what}: {exc}") from exc
199
+ try:
200
+ return _created(response, what=what)
201
+ finally:
202
+ response.close()
203
+
204
+
205
+ def create_word_document(
206
+ *,
207
+ api: PublicApi,
208
+ name: str | None,
209
+ parent_folder_id: str | None,
210
+ workspace_id: str | None,
211
+ ) -> CreatedDocument:
212
+ """Have Athena create a Word document holding its default template."""
213
+ payload: dict[str, str] = {"asset_type": "word_document"}
214
+ if name is not None:
215
+ payload["title"] = name
216
+ if parent_folder_id is not None:
217
+ payload["parent_folder_id"] = parent_folder_id
218
+ if workspace_id is not None:
219
+ payload["workspace_id"] = workspace_id
220
+ session = _create_session()
221
+ try:
222
+ return _post(
223
+ session=session,
224
+ url=f"{api.base}/assets/create",
225
+ what="a Word document",
226
+ json=payload,
227
+ headers=api.headers(),
228
+ timeout=CREATE_TIMEOUT_SECONDS,
229
+ )
230
+ finally:
231
+ session.close()
232
+
233
+
234
+ def create_word_document_from_file(
235
+ *,
236
+ api: PublicApi,
237
+ docx_path: str,
238
+ title: str,
239
+ parent_folder_id: str | None,
240
+ workspace_id: str | None,
241
+ source_asset_id: str | None,
242
+ timeout: float,
243
+ ) -> CreatedDocument:
244
+ """Have Athena create a Word document holding the ``.docx`` at ``docx_path``.
245
+
246
+ Athena answers once the file is imported, and leaves nothing behind when the
247
+ import fails.
248
+ """
249
+ params: dict[str, str] = {"title": title}
250
+ if parent_folder_id is not None:
251
+ params["parent_folder_id"] = parent_folder_id
252
+ if workspace_id is not None:
253
+ params["workspace_id"] = workspace_id
254
+ if source_asset_id is not None:
255
+ params["source_asset_id"] = source_asset_id
256
+ file_path = Path(docx_path)
257
+ session = _create_session()
258
+ try:
259
+ with file_path.open("rb") as handle:
260
+ return _post(
261
+ session=session,
262
+ url=f"{api.base}/assets/create-from-file",
263
+ what=f"a Word document from {file_path.name}",
264
+ params=params,
265
+ files={"file": (file_path.name, handle, _DOCX_CONTENT_TYPE)},
266
+ headers=api.headers(),
267
+ timeout=max(timeout, CREATE_TIMEOUT_SECONDS),
268
+ )
269
+ finally:
270
+ session.close()
@@ -282,7 +282,11 @@ class Document:
282
282
  api_key: Athena API key (PropelAuth user API key) or
283
283
  access token. Falls back to ``$ATHENA_DOCX_API_KEY``, then
284
284
  ``$ATHENA_API_KEY``, as every other call does; the upload path
285
- (``docx=``) sends the same key to agora.
285
+ (``docx=``) sends the same key to agora. With neither of the
286
+ first two set and both ``$ATHENA_API_KEY`` and
287
+ ``$ATHENA_API_URL`` set (a computer's or session VM's scoped
288
+ key), Athena's public API creates the document instead, from
289
+ the template or from ``docx`` (``docx._public_create``).
286
290
  parent_folder_id: Optional parent folder; defaults to
287
291
  the source document's folder when source_asset_id is set,
288
292
  otherwise workspace root.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "athena-python-docx"
7
- version = "0.44.0"
7
+ version = "0.45.0"
8
8
  description = "Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -3,9 +3,9 @@
3
3
  Order for a call on an existing Word document: ``api_key=``;
4
4
  ``ATHENA_DOCX_API_KEY``; a token minted from Athena's public API with
5
5
  ``ATHENA_API_KEY`` (when ``ATHENA_API_URL`` is set too); else ``ATHENA_API_KEY``
6
- itself. Creating a document keeps the key. Nothing here reaches a real
7
- service: every request goes through ``requests.Session.request`` (or, for the
8
- create path, ``urllib``), faked below.
6
+ itself. Creating a document in the token case goes through Athena's public
7
+ API (``test_public_create.py``). Nothing here reaches a real service: every
8
+ request goes through ``requests.Session.request``, faked below.
9
9
  """
10
10
 
11
11
  from __future__ import annotations
@@ -256,29 +256,22 @@ def test_athena_api_url_works_with_and_without_the_public_api_prefix(
256
256
  assert [call.url for call in world.mint_calls()] == [MINT_URL]
257
257
 
258
258
 
259
- def test_creating_a_document_keeps_athena_api_key_and_mints_nothing(world: _World) -> None:
260
- sent: list[Any] = []
261
-
262
- class _Created:
263
- def __enter__(self) -> _Created:
264
- return self
265
-
266
- def __exit__(self, *_: object) -> None:
267
- return None
268
-
269
- def read(self) -> bytes:
270
- return json.dumps(
271
- {"assetId": ASSET, "name": "Doc", "workspaceId": "ws_1"}
272
- ).encode()
273
-
274
- def _capture(request: Any, **_: Any) -> _Created:
275
- sent.append(request)
276
- return _Created()
259
+ def test_creating_a_document_goes_through_athena_and_mints_nothing(world: _World) -> None:
260
+ # A document that does not exist has no token, and docx-studio refuses the
261
+ # scoped key: Athena's public API creates it (docx._public_create).
262
+ world.studio.append(
263
+ _response(200, {"asset_id": ASSET, "title": "Doc", "workspace_id": "ws_1"})
264
+ )
277
265
 
278
- with patch("docx._http.urllib.request.urlopen", side_effect=_capture):
279
- create_empty_document(name="Doc")
266
+ with patch("docx._http.urllib.request.urlopen") as urlopen:
267
+ created = create_empty_document(name="Doc")
280
268
 
281
- assert [request.get_header("Authorization") for request in sent] == [f"Bearer {SCOPED_KEY}"]
269
+ urlopen.assert_not_called()
270
+ assert created == {"asset_id": ASSET, "name": "Doc", "workspace_id": "ws_1"}
271
+ [call] = world.calls
272
+ assert (call.method, call.url) == ("POST", f"{AGORA}/api/v0/assets/create")
273
+ assert call.headers["X-API-KEY"] == SCOPED_KEY
274
+ assert call.bearer is None
282
275
  assert world.mint_calls() == []
283
276
 
284
277
 
@@ -459,6 +452,28 @@ def test_a_503_falls_back_to_a_studio_key_set_since(
459
452
  assert len(world.mint_calls()) == 1
460
453
 
461
454
 
455
+ def test_an_athena_without_the_mint_route_gets_athena_api_key_as_before(world: _World) -> None:
456
+ # An Athena older than the route: FastAPI's bare 404 for a path no route matches.
457
+ world.mints.append(_response(404, {"detail": "Not Found"}))
458
+ world.studio.extend([_response(200, {"pageCount": 1, "pages": []}), _applied()])
459
+ client = _client()
460
+
461
+ client.get_layout(ASSET)
462
+ _batch(client)
463
+
464
+ assert len(world.mint_calls()) == 1
465
+ assert [call.bearer for call in world.studio_calls()] == [SCOPED_KEY, SCOPED_KEY]
466
+
467
+
468
+ def test_athenas_own_asset_not_found_stays_final(world: _World) -> None:
469
+ world.mints.append(_response(404, {"detail": "Asset not found."}))
470
+
471
+ with pytest.raises(NotFoundError, match="Asset not found"):
472
+ _batch(_client())
473
+
474
+ assert world.studio_calls() == []
475
+
476
+
462
477
  def test_an_asset_another_studio_edits_is_never_sent_its_token(world: _World) -> None:
463
478
  world.mints.append(world.mint_ok(audience="xlsx-studio"))
464
479