athena-python-docx 0.9.0__tar.gz → 0.10.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.
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/CLAUDE.md +19 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/PKG-INFO +1 -1
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_http_doc.py +6 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/api.py +56 -8
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/commands.py +28 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/document.py +45 -39
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/errors.py +37 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/table.py +90 -48
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/pyproject.toml +1 -1
- athena_python_docx-0.10.0/scripts/smoke_test_block_not_found.py +175 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/fake_session.py +68 -0
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +12 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -1
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/18_table_cell_text.json +9 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -3
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/23_nested_table.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +1 -3
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -2
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/35_full_report.json +9 -33
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/40_large_table_10x10.json +103 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +1 -5
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/49_resume_layout.json +3 -12
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +12 -48
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -1
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +793 -1993
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/68_invoice.json +62 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -1
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/72_legal_contract.json +6 -24
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +20 -80
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +9 -27
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +24 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -1
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/91_many_small_tables.json +153 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +3 -12
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex04_50x50_table.json +53 -0
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +5 -0
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/mega10_api_documentation.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex10_complex_bom.json +126 -113
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +80 -320
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -1
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/rw10_colored_grid_table.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/ex14_styled_report_table.json +36 -69
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +84 -336
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +13 -52
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +18 -72
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +21 -98
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +20 -88
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/ex14_styled_report_table.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +44 -75
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +8 -36
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json → athena_python_docx-0.10.0/tests/fidelity/op_snapshots/mega10_api_documentation.json +104 -97
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +12 -36
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +12 -36
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/rw08_table_merged_header.json +13 -0
- athena_python_docx-0.10.0/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +148 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +1 -4
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/reports/gap_report.json +1 -1
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/snapshots/athena_latest.json +0 -50
- athena_python_docx-0.10.0/tests/test_document_asset_id_property.py +52 -0
- athena_python_docx-0.10.0/tests/test_document_factory_validation.py +52 -0
- athena_python_docx-0.10.0/tests/test_e2e_partial_failure_cascade.py +278 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_parity_misc.py +4 -2
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_document_audit.py +55 -61
- athena_python_docx-0.10.0/tests/test_table_set_cell_perf.py +127 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_wire_contract.py +9 -0
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -24
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -27
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -403
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/68_invoice.json +0 -114
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -54
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -453
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -203
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -8
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -596
- athena_python_docx-0.9.0/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -35
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/.gitignore +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/README.md +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_http.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/client.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/comments.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/section.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/settings.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/shape.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/shared.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/paragraph.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/run.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/docx/typing.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/scripts/publish.sh +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/runner.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/tests/test_zod_wire_contract.py +0 -0
- {athena_python_docx-0.9.0 → athena_python_docx-0.10.0}/uv.lock +0 -0
|
@@ -88,13 +88,28 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
88
88
|
hits `POST {base_url}/docs/empty`. The constructor positional-arg
|
|
89
89
|
shape (`Document(asset_id)`) is preserved for parity.
|
|
90
90
|
|
|
91
|
-
- **`Document.
|
|
92
|
-
|
|
91
|
+
- **`Document.asset_id: str`** read-only property — the Athena asset
|
|
92
|
+
id this Document is bound to (`asset_<uuid>`). Agent-callable so
|
|
93
|
+
the typical pattern `doc = Document.create(...); print(doc.asset_id)`
|
|
94
|
+
works without reaching into `doc._session._asset_id`. Stock
|
|
95
|
+
python-docx has no analogue (it operates on local files), so this
|
|
96
|
+
is an Athena-only addition. Mirrors the parallel public accessors
|
|
97
|
+
on the other studios: `Workbook.workbook_id` (xlsx) and
|
|
98
|
+
`Presentation.deck_id` (pptx).
|
|
99
|
+
|
|
100
|
+
- **`Document.save(path_or_stream=None)`** — argument is optional and,
|
|
101
|
+
when supplied, raises
|
|
102
|
+
:class:`docx.errors.LocalSaveTargetNotSupportedError`. Stock
|
|
103
|
+
python-docx requires it and `TypeError`s on no-arg, but in an
|
|
93
104
|
asset-backed SDK there is no local file to write — writes are always
|
|
94
105
|
in-place against the Y.Doc. Forcing the upstream signature broke
|
|
95
106
|
every agent invocation that reflexively called `doc.save()` (a
|
|
96
|
-
near-universal Python pattern), so
|
|
97
|
-
|
|
107
|
+
near-universal Python pattern), so the no-arg form is supported.
|
|
108
|
+
When a path or stream IS supplied, the SDK cannot fulfill the
|
|
109
|
+
implied "write bytes to this target" contract, so the call raises
|
|
110
|
+
loudly rather than silently flushing — agents must use Olympus's
|
|
111
|
+
Export DOCX (which goes through the SuperDoc session that already
|
|
112
|
+
has the bytes) instead of expecting a local file.
|
|
98
113
|
|
|
99
114
|
- **`Document.track_revisions: bool`** — when `True`, all subsequent
|
|
100
115
|
mutations are recorded as tracked revisions instead of direct edits.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -30,6 +30,7 @@ format is now typed end-to-end either way.
|
|
|
30
30
|
from __future__ import annotations
|
|
31
31
|
|
|
32
32
|
import json
|
|
33
|
+
import os
|
|
33
34
|
from typing import Any
|
|
34
35
|
|
|
35
36
|
import requests
|
|
@@ -106,6 +107,7 @@ from docx.commands import (
|
|
|
106
107
|
TablesSetRowHeight,
|
|
107
108
|
TablesSetStyle,
|
|
108
109
|
TablesSetTableOptions,
|
|
110
|
+
TableSetCell,
|
|
109
111
|
TrackChangesDecide,
|
|
110
112
|
TrackChangesGet,
|
|
111
113
|
TrackChangesList,
|
|
@@ -372,6 +374,9 @@ def _http_post_json(
|
|
|
372
374
|
"Accept": "application/json",
|
|
373
375
|
"User-Agent": _user_agent(),
|
|
374
376
|
}
|
|
377
|
+
custom_attr = os.environ.get("ATHENA_DOCX_CUSTOM_ATTRIBUTIONS")
|
|
378
|
+
if custom_attr:
|
|
379
|
+
headers["X-Custom-Attributions"] = custom_attr
|
|
375
380
|
try:
|
|
376
381
|
resp = session.post(
|
|
377
382
|
url,
|
|
@@ -647,6 +652,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
|
|
|
647
652
|
"tables.set_cell_properties": TablesSetCellProperties,
|
|
648
653
|
"tables.set_column_width": TablesSetColumnWidth,
|
|
649
654
|
"tables.set_row_height": TablesSetRowHeight,
|
|
655
|
+
"tables.set_cell": TableSetCell,
|
|
650
656
|
# Images (mutations)
|
|
651
657
|
"images.set_size": SetImageSize,
|
|
652
658
|
"images.set_alt_text": SetImageAltText,
|
|
@@ -6,7 +6,10 @@ python-docx signature:
|
|
|
6
6
|
Our signature deviates from the path-based one because we don't open
|
|
7
7
|
.docx files from disk — we open Y.Doc assets from Keryx. The parameter
|
|
8
8
|
is reused: pass an asset_id string where python-docx would take a file
|
|
9
|
-
path.
|
|
9
|
+
path. The id MUST be ``asset_<uuid>``; anything else (a title, a file
|
|
10
|
+
path, etc.) raises ``ValueError`` before any HTTP request. To mint a
|
|
11
|
+
new asset, call ``Document.create(name=...)`` and reuse the returned
|
|
12
|
+
``doc.asset_id`` on subsequent ``Document(...)`` opens.
|
|
10
13
|
|
|
11
14
|
For net-new asset creation, use the classmethod ``Document.create()``
|
|
12
15
|
(see ``docx.document``). Stock python-docx returns a blank document
|
|
@@ -18,8 +21,18 @@ write that has to happen first. ``Document.create()`` handles that via
|
|
|
18
21
|
|
|
19
22
|
from __future__ import annotations
|
|
20
23
|
|
|
24
|
+
import re
|
|
25
|
+
|
|
21
26
|
from docx.document import Document as _Document
|
|
22
27
|
|
|
28
|
+
# Asset-id shape validation. Athena SuperDocument assets are
|
|
29
|
+
# ``asset_<uuid>``. Rejecting anything else up front prevents the
|
|
30
|
+
# common agent failure mode of passing a document TITLE
|
|
31
|
+
# (``Document("Q4 Report Draft")``) instead of its id, which would
|
|
32
|
+
# otherwise round-trip through the docx-studio session and fail with
|
|
33
|
+
# an opaque server error.
|
|
34
|
+
_ASSET_ID_PATTERN = re.compile(r"^asset_[A-Za-z0-9_-]+$")
|
|
35
|
+
|
|
23
36
|
|
|
24
37
|
def Document(
|
|
25
38
|
docx: str | None = None,
|
|
@@ -67,14 +80,49 @@ def Document(
|
|
|
67
80
|
"To create a brand-new document, call "
|
|
68
81
|
"Document.create(name=..., base_url=..., api_key=...).",
|
|
69
82
|
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
if not _ASSET_ID_PATTERN.match(docx):
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Document({docx!r}) is not a valid SuperDocument asset id. "
|
|
86
|
+
f"Asset ids look like 'asset_<uuid>' "
|
|
87
|
+
f"(e.g., 'asset_3a9328bc-9c1c-4498-be8f-bda3883276f5'). To "
|
|
88
|
+
f"open an existing document, pass its asset id — NOT its "
|
|
89
|
+
f"title. To create a new document titled {docx!r}, call "
|
|
90
|
+
f"Document.create(name={docx!r}) and reuse the returned "
|
|
91
|
+
f"document's asset id on subsequent calls in the same "
|
|
92
|
+
f"conversation."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# PTC: surface document open as its own sub-tool-card so the
|
|
96
|
+
# frontend can react (e.g., auto-open the asset tab). The paired
|
|
97
|
+
# ``Document.create()`` path emits ``CreateDocument``; this open
|
|
98
|
+
# path emits ``OpenDocument`` with the asset id.
|
|
99
|
+
from docx import _ptc
|
|
100
|
+
|
|
101
|
+
call_id = _ptc.emit_begin("OpenDocument", {"assetId": docx})
|
|
102
|
+
try:
|
|
103
|
+
doc = _Document(
|
|
104
|
+
asset_id=docx,
|
|
105
|
+
http_base_url=base_url,
|
|
106
|
+
http_api_key=api_key,
|
|
107
|
+
user_name=user_name,
|
|
108
|
+
user_email=user_email,
|
|
109
|
+
track_revisions=track_revisions,
|
|
110
|
+
)
|
|
111
|
+
except Exception as exc:
|
|
112
|
+
_ptc.emit_end(
|
|
113
|
+
call_id=call_id,
|
|
114
|
+
tool_name="OpenDocument",
|
|
115
|
+
result={"ok": False, "error": str(exc)},
|
|
116
|
+
is_error=True,
|
|
117
|
+
)
|
|
118
|
+
raise
|
|
119
|
+
_ptc.emit_end(
|
|
120
|
+
call_id=call_id,
|
|
121
|
+
tool_name="OpenDocument",
|
|
122
|
+
result={"ok": True, "assetId": docx},
|
|
123
|
+
is_error=False,
|
|
77
124
|
)
|
|
125
|
+
return doc
|
|
78
126
|
|
|
79
127
|
|
|
80
128
|
# Re-export the classmethod factories at module level so callers can
|
|
@@ -140,6 +140,33 @@ class Insert(Command):
|
|
|
140
140
|
content: dict[str, Any] | None = None
|
|
141
141
|
|
|
142
142
|
|
|
143
|
+
@dataclass
|
|
144
|
+
class TableSetCell(Command):
|
|
145
|
+
"""Address a single table cell by ``(table_node_id, row, col)`` and insert
|
|
146
|
+
``content`` into it. The applier resolves the cell's real nodeId
|
|
147
|
+
server-side (via one batch-wide ``tables.getCells`` call cached per
|
|
148
|
+
table), so the SDK doesn't need a prior ``tables.get_cells`` query —
|
|
149
|
+
each ``_Cell.text = …`` skips 1 HTTP round-trip and the whole table
|
|
150
|
+
flushes in one batch.
|
|
151
|
+
|
|
152
|
+
Buffered, not response-bearing. Placement defaults to ``insideEnd``
|
|
153
|
+
on the apps/api side (matches the prior ``_Cell.text`` setter
|
|
154
|
+
semantics: APPEND into the cell's existing paragraph, which produces
|
|
155
|
+
``cell.text == value`` for a freshly created empty cell).
|
|
156
|
+
|
|
157
|
+
``table_node_id`` may be a client-side UUID — the applier resolves
|
|
158
|
+
it through the per-batch ``clientIdMap`` set by the preceding
|
|
159
|
+
``CreateTable``, so a freshly created table can be populated in the
|
|
160
|
+
same flush.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
table_node_id: str
|
|
164
|
+
row_index: int
|
|
165
|
+
column_index: int
|
|
166
|
+
content: dict[str, Any]
|
|
167
|
+
placement: str | None = None
|
|
168
|
+
|
|
169
|
+
|
|
143
170
|
@dataclass
|
|
144
171
|
class Replace(Command):
|
|
145
172
|
target: dict[str, Any]
|
|
@@ -899,6 +926,7 @@ __all__ = [
|
|
|
899
926
|
"TablesSetCellProperties",
|
|
900
927
|
"TablesSetColumnWidth",
|
|
901
928
|
"TablesSetRowHeight",
|
|
929
|
+
"TableSetCell",
|
|
902
930
|
# Images (mutations)
|
|
903
931
|
"SetImageSize",
|
|
904
932
|
# Queries
|
|
@@ -17,13 +17,16 @@ from __future__ import annotations
|
|
|
17
17
|
import base64
|
|
18
18
|
import io
|
|
19
19
|
import sys
|
|
20
|
-
import warnings
|
|
21
20
|
from contextlib import contextmanager
|
|
22
21
|
from typing import TYPE_CHECKING, BinaryIO, Generator, Iterator
|
|
23
22
|
|
|
24
23
|
from docx._batching import run_sync
|
|
25
24
|
from docx.client import Session
|
|
26
|
-
from docx.errors import
|
|
25
|
+
from docx.errors import (
|
|
26
|
+
DocumentClosedError,
|
|
27
|
+
LocalSaveTargetNotSupportedError,
|
|
28
|
+
ValidationError,
|
|
29
|
+
)
|
|
27
30
|
|
|
28
31
|
# python-docx re-exports a subset of symbols at docx.document; mirror those
|
|
29
32
|
# so `from docx.document import Emu` etc. works.
|
|
@@ -121,20 +124,6 @@ def _classify_list_style(style_id: str | None) -> tuple[str, int] | None:
|
|
|
121
124
|
return (kind, level)
|
|
122
125
|
|
|
123
126
|
|
|
124
|
-
class IgnoredSaveTargetWarning(UserWarning):
|
|
125
|
-
"""Emitted when ``Document.save(path_or_stream=...)`` is called with a
|
|
126
|
-
non-None argument.
|
|
127
|
-
|
|
128
|
-
The SDK is asset-backed: edits are flushed in place against the
|
|
129
|
-
Y.Doc, and the ``path_or_stream`` parameter is accepted only for
|
|
130
|
-
parity-friendly call sites (see :meth:`Document.save`). A caller
|
|
131
|
-
passing a path or stream almost certainly expects a local-file
|
|
132
|
-
export, which this SDK cannot perform. Surfacing a warning makes
|
|
133
|
-
the silent gap visible without breaking agent-generated code that
|
|
134
|
-
reflexively calls ``doc.save()`` with no args.
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
|
|
138
127
|
class Document:
|
|
139
128
|
"""A Word document backed by a Superdoc/Keryx Y.Doc.
|
|
140
129
|
|
|
@@ -258,6 +247,20 @@ class Document:
|
|
|
258
247
|
|
|
259
248
|
# ---- Public properties ----
|
|
260
249
|
|
|
250
|
+
@property
|
|
251
|
+
def asset_id(self) -> str:
|
|
252
|
+
"""Athena asset id this Document is bound to (``asset_<uuid>``).
|
|
253
|
+
|
|
254
|
+
Agent-callable accessor — use this to capture the id of a
|
|
255
|
+
``Document.create(...)`` so subsequent ``Document(asset_id)``
|
|
256
|
+
opens can target the same document in later tool calls.
|
|
257
|
+
|
|
258
|
+
DEVIATION FROM python-docx: stock python-docx has no analogue
|
|
259
|
+
because it operates on local files, not assets. Documented in
|
|
260
|
+
``docs/API_PARITY_EXCEPTIONS.md``.
|
|
261
|
+
"""
|
|
262
|
+
return self._session.asset_id
|
|
263
|
+
|
|
261
264
|
@property
|
|
262
265
|
def paragraphs(self) -> list["Paragraph"]:
|
|
263
266
|
"""Return all paragraphs in document order.
|
|
@@ -939,7 +942,12 @@ class Document:
|
|
|
939
942
|
),
|
|
940
943
|
)
|
|
941
944
|
|
|
942
|
-
tbl = Table(
|
|
945
|
+
tbl = Table(
|
|
946
|
+
session=self._session,
|
|
947
|
+
node_id=node_id,
|
|
948
|
+
rows=rows,
|
|
949
|
+
columns=cols,
|
|
950
|
+
)
|
|
943
951
|
self._register_proxy_id(client_node_id, tbl)
|
|
944
952
|
return tbl
|
|
945
953
|
|
|
@@ -1108,30 +1116,28 @@ class Document:
|
|
|
1108
1116
|
optional. Stock python-docx requires it and raises ``TypeError``
|
|
1109
1117
|
on ``save()`` no-arg, but in this asset-backed SDK there is no
|
|
1110
1118
|
local file to write to — writes are always in-place against the
|
|
1111
|
-
Y.Doc. Agent-generated code reflexively calls ``doc.save()
|
|
1112
|
-
forcing the upstream signature broke
|
|
1113
|
-
(
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
silent success and no file on disk.
|
|
1119
|
+
Y.Doc. Agent-generated code reflexively calls ``doc.save()``;
|
|
1120
|
+
forcing the upstream signature broke common agent call patterns,
|
|
1121
|
+
so no-arg ``doc.save()`` is supported.
|
|
1122
|
+
|
|
1123
|
+
When ``path_or_stream`` IS supplied (e.g. ``doc.save("./out.docx")``
|
|
1124
|
+
or ``doc.save(BytesIO())``), this raises
|
|
1125
|
+
:class:`docx.errors.LocalSaveTargetNotSupportedError`. The SDK
|
|
1126
|
+
cannot fulfill the implied contract of "write bytes to this
|
|
1127
|
+
target"; previously the call emitted a warning and silently
|
|
1128
|
+
flushed, leaving callers with no file on disk and no error.
|
|
1129
|
+
Raising forces the caller to address the gap explicitly — use
|
|
1130
|
+
Olympus's Export DOCX (which goes through the SuperDoc session
|
|
1131
|
+
that already has the bytes).
|
|
1125
1132
|
"""
|
|
1126
1133
|
if path_or_stream is not None:
|
|
1127
|
-
|
|
1128
|
-
"Document.save(path_or_stream=...)
|
|
1129
|
-
"athena-python-docx is
|
|
1130
|
-
"
|
|
1131
|
-
"
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
stacklevel=2,
|
|
1134
|
+
raise LocalSaveTargetNotSupportedError(
|
|
1135
|
+
"Document.save(path_or_stream=...) cannot write to a "
|
|
1136
|
+
"local file or stream — athena-python-docx is "
|
|
1137
|
+
"asset-backed and edits flush in place against the "
|
|
1138
|
+
f"Y.Doc. Got {path_or_stream!r}. Call doc.save() with "
|
|
1139
|
+
"no arguments to flush, or use Olympus's Export DOCX "
|
|
1140
|
+
"to obtain a .docx file."
|
|
1135
1141
|
)
|
|
1136
1142
|
self._flush()
|
|
1137
1143
|
|
|
@@ -31,10 +31,24 @@ class DocxError(Exception):
|
|
|
31
31
|
:meth:`with_partial_applied` factory helper at raise sites instead.
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
def __getattr__(self, name: str) -> list[dict]:
|
|
35
|
+
"""Lazy default for ``partial_applied`` — returns an empty list
|
|
36
|
+
when the attribute hasn't been set via :meth:`with_partial_applied`.
|
|
37
|
+
|
|
38
|
+
Using ``__getattr__`` (only called when ordinary attribute
|
|
39
|
+
lookup misses) instead of a class-level mutable default avoids
|
|
40
|
+
the footgun where ``exc.partial_applied.append(x)`` on a
|
|
41
|
+
legacy-raised error would mutate a shared list and make every
|
|
42
|
+
subsequent ``DocxError`` look partially applied. Each call here
|
|
43
|
+
returns a fresh empty list; mutating it has no cross-instance
|
|
44
|
+
effect.
|
|
45
|
+
"""
|
|
46
|
+
if name == "partial_applied":
|
|
47
|
+
return []
|
|
48
|
+
# Match Python's default ``AttributeError`` for unknown attrs.
|
|
49
|
+
raise AttributeError(
|
|
50
|
+
f"{type(self).__name__!r} object has no attribute {name!r}",
|
|
51
|
+
)
|
|
38
52
|
|
|
39
53
|
def with_partial_applied(
|
|
40
54
|
self,
|
|
@@ -48,6 +62,8 @@ class DocxError(Exception):
|
|
|
48
62
|
raise DocxError("...").with_partial_applied(prefix)
|
|
49
63
|
"""
|
|
50
64
|
if applied:
|
|
65
|
+
# Writes to ``self.__dict__`` — subsequent reads bypass
|
|
66
|
+
# ``__getattr__`` entirely and see the per-instance list.
|
|
51
67
|
self.partial_applied = list(applied)
|
|
52
68
|
return self
|
|
53
69
|
|
|
@@ -71,6 +87,23 @@ class DocumentClosedError(DocxError):
|
|
|
71
87
|
"""Raised when operating on a closed Document."""
|
|
72
88
|
|
|
73
89
|
|
|
90
|
+
class LocalSaveTargetNotSupportedError(DocxError, NotImplementedError):
|
|
91
|
+
"""Raised when ``Document.save(path_or_stream=...)`` is called with a
|
|
92
|
+
non-None argument.
|
|
93
|
+
|
|
94
|
+
The SDK is asset-backed: edits flush in place against the Y.Doc, so
|
|
95
|
+
there is no local file or stream to write to. The bare ``doc.save()``
|
|
96
|
+
no-arg form remains supported as the documented deviation from stock
|
|
97
|
+
python-docx (see :meth:`docx.document.Document.save`). To get a
|
|
98
|
+
``.docx`` file out, use Olympus's Export DOCX action — the SuperDoc
|
|
99
|
+
session already has the bytes the caller wanted.
|
|
100
|
+
|
|
101
|
+
Subclasses :class:`NotImplementedError` so a generic
|
|
102
|
+
``except NotImplementedError`` catches it without importing the
|
|
103
|
+
typed class.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
|
|
74
107
|
class ValidationError(DocxError):
|
|
75
108
|
"""Raised when SDK-level validation fails (bad args, out-of-range indices)."""
|
|
76
109
|
|
|
@@ -234,9 +234,26 @@ def _collect_block_ids(
|
|
|
234
234
|
|
|
235
235
|
|
|
236
236
|
class Table:
|
|
237
|
-
def __init__(
|
|
237
|
+
def __init__(
|
|
238
|
+
self,
|
|
239
|
+
*,
|
|
240
|
+
session: "Session",
|
|
241
|
+
node_id: str,
|
|
242
|
+
rows: int | None = None,
|
|
243
|
+
columns: int | None = None,
|
|
244
|
+
) -> None:
|
|
238
245
|
self._session: "Session" = session
|
|
239
246
|
self._node_id: str = node_id
|
|
247
|
+
# Locally-cached grid dimensions. Populated by
|
|
248
|
+
# ``Document.add_table`` (which knows the rows/cols up-front)
|
|
249
|
+
# so ``Table.cell()`` can validate bounds without round-tripping
|
|
250
|
+
# to ``tables.get``. Stays ``None`` for Tables resolved later
|
|
251
|
+
# via ``find`` / iteration; ``cell()`` falls back to
|
|
252
|
+
# ``_fresh_node_info()`` in that case. ``tables.insert_row`` /
|
|
253
|
+
# ``tables.insert_column`` invalidate this cache so the next
|
|
254
|
+
# access re-fetches authoritative counts.
|
|
255
|
+
self._cached_rows: int | None = rows
|
|
256
|
+
self._cached_cols: int | None = columns
|
|
240
257
|
|
|
241
258
|
def _fresh_node_info(self) -> tuple[str, dict]:
|
|
242
259
|
"""Resolve the live nodeId and return ``(node_id, info_dict)``.
|
|
@@ -332,21 +349,35 @@ class Table:
|
|
|
332
349
|
|
|
333
350
|
Negative indices are accepted Python-style (``-1`` is the last
|
|
334
351
|
row/column).
|
|
352
|
+
|
|
353
|
+
Fast path: when the Table proxy was constructed with known
|
|
354
|
+
dimensions (``Document.add_table`` and ``Table.insert_row`` /
|
|
355
|
+
``insert_column`` keep this cache current), bounds-check
|
|
356
|
+
against the local cache without round-tripping to
|
|
357
|
+
``tables.get``. This is what keeps a 30-cell write loop at
|
|
358
|
+
zero query-shaped HTTP calls — pre-cache this was one
|
|
359
|
+
``tables.get`` per ``cell()`` access.
|
|
335
360
|
"""
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
361
|
+
row_count: int
|
|
362
|
+
col_count: int
|
|
363
|
+
if self._cached_rows is not None and self._cached_cols is not None:
|
|
364
|
+
row_count = self._cached_rows
|
|
365
|
+
col_count = self._cached_cols
|
|
366
|
+
else:
|
|
367
|
+
_, info_dict = self._fresh_node_info()
|
|
368
|
+
row_count = int(
|
|
369
|
+
info_dict.get("rows")
|
|
370
|
+
or info_dict.get("rowCount")
|
|
371
|
+
or (info_dict.get("table", {}) or {}).get("rows")
|
|
372
|
+
or 0,
|
|
373
|
+
)
|
|
374
|
+
col_count = int(
|
|
375
|
+
info_dict.get("columns")
|
|
376
|
+
or info_dict.get("cols")
|
|
377
|
+
or info_dict.get("columnCount")
|
|
378
|
+
or (info_dict.get("table", {}) or {}).get("columns")
|
|
379
|
+
or 0,
|
|
380
|
+
)
|
|
350
381
|
# Normalize negative indices the same way list[] does.
|
|
351
382
|
if row_idx < 0:
|
|
352
383
|
row_idx += row_count
|
|
@@ -399,6 +430,10 @@ class Table:
|
|
|
399
430
|
},
|
|
400
431
|
),
|
|
401
432
|
)
|
|
433
|
+
# Keep the bounds-check cache current so the next ``cell()``
|
|
434
|
+
# access still hits the fast path.
|
|
435
|
+
if self._cached_rows is not None:
|
|
436
|
+
self._cached_rows += 1
|
|
402
437
|
return _Row(table=self, index=row_count)
|
|
403
438
|
|
|
404
439
|
def add_column(self, width: "Length") -> "_Column":
|
|
@@ -432,6 +467,9 @@ class Table:
|
|
|
432
467
|
},
|
|
433
468
|
),
|
|
434
469
|
)
|
|
470
|
+
# Keep the bounds-check cache current.
|
|
471
|
+
if self._cached_cols is not None:
|
|
472
|
+
self._cached_cols += 1
|
|
435
473
|
new_col = _Column(table=self, index=col_count)
|
|
436
474
|
new_col.width = width
|
|
437
475
|
return new_col
|
|
@@ -1009,10 +1047,10 @@ class _Cell:
|
|
|
1009
1047
|
|
|
1010
1048
|
The cell's single inner paragraph is addressed indirectly — Superdoc
|
|
1011
1049
|
doesn't expose a paragraph ref that's usable as a `blockId` for text
|
|
1012
|
-
selections.
|
|
1013
|
-
|
|
1014
|
-
cell's existing paragraph. For a freshly-created (empty)
|
|
1015
|
-
produces `cell.text == value` on read-back.
|
|
1050
|
+
selections. The apps/api applier wraps a `tables.getCells` lookup +
|
|
1051
|
+
a `doc.insert` with placement=insideEnd, which APPENDS inline runs
|
|
1052
|
+
to the cell's existing paragraph. For a freshly-created (empty)
|
|
1053
|
+
cell this produces `cell.text == value` on read-back.
|
|
1016
1054
|
|
|
1017
1055
|
For cells that already contain text, callers who truly want "replace"
|
|
1018
1056
|
semantics should first resolve the cell's paragraph via `doc.find`
|
|
@@ -1028,34 +1066,27 @@ class _Cell:
|
|
|
1028
1066
|
raise TypeError(
|
|
1029
1067
|
f"_Cell.text must be a str; got {type(value).__name__}",
|
|
1030
1068
|
)
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
#
|
|
1039
|
-
# (paragraph/heading/table/image/list/sectionBreak/sdt/tableOfContents).
|
|
1040
|
-
# We need to materialize ``value`` into a
|
|
1041
|
-
# ``{kind:"paragraph", paragraph:{inlines:[...]}}`` fragment.
|
|
1069
|
+
# As of 0.10.0 the setter buffers a ``TableSetCell`` command
|
|
1070
|
+
# addressed by ``(table_node_id, row, col)`` and skips both
|
|
1071
|
+
# eager queries that used to fire per cell — the
|
|
1072
|
+
# ``Table._fresh_node_info()`` call (``tables.get`` query)
|
|
1073
|
+
# AND the ``_cell_info()`` call (``tables.get_cells`` query).
|
|
1074
|
+
# The apps/api applier resolves the cell nodeId server-side
|
|
1075
|
+
# against a per-batch cache so N cell writes against one table
|
|
1076
|
+
# share one ``tables.getCells`` call.
|
|
1042
1077
|
#
|
|
1043
|
-
#
|
|
1044
|
-
#
|
|
1045
|
-
#
|
|
1046
|
-
# the
|
|
1047
|
-
#
|
|
1048
|
-
# ``Insert`` no longer being response-bearing (0.8.0), a 30-cell
|
|
1049
|
-
# table assignment now ships in a single ``doc.insert`` batch
|
|
1050
|
-
# instead of 60 sequential round-trips. See
|
|
1078
|
+
# Pre-0.10.0 a 30-cell table assignment was ~60 HTTP round-
|
|
1079
|
+
# trips (one ``tables.get`` + one ``tables.get_cells`` per
|
|
1080
|
+
# cell); post-0.10.0 it's a single ``POST /commands`` batch
|
|
1081
|
+
# containing the 30 TableSetCell commands plus whatever else
|
|
1082
|
+
# was already buffered. See
|
|
1051
1083
|
# ``docx-studio/PERFORMANCE_BATCHING_ANALYSIS.md``.
|
|
1052
1084
|
#
|
|
1053
|
-
#
|
|
1054
|
-
#
|
|
1055
|
-
#
|
|
1056
|
-
#
|
|
1057
|
-
|
|
1058
|
-
# destroying the table structure
|
|
1085
|
+
# For plain text we build the fragment client-side. For
|
|
1086
|
+
# markdown content we still need one eager
|
|
1087
|
+
# ``markdown_to_fragment`` query (the parsed fragment isn't
|
|
1088
|
+
# something the apps/api applier can build for us yet).
|
|
1089
|
+
session = self._table._session
|
|
1059
1090
|
try:
|
|
1060
1091
|
fragment: dict
|
|
1061
1092
|
if _is_plain_text(value):
|
|
@@ -1092,11 +1123,22 @@ class _Cell:
|
|
|
1092
1123
|
],
|
|
1093
1124
|
},
|
|
1094
1125
|
}
|
|
1126
|
+
# ``self._table._node_id`` is the raw client-or-server id
|
|
1127
|
+
# the Table proxy currently holds. The applier resolves it
|
|
1128
|
+
# through the per-batch clientIdMap so a freshly-created
|
|
1129
|
+
# table (still on its client UUID locally) routes to the
|
|
1130
|
+
# real id without forcing a flush here.
|
|
1131
|
+
#
|
|
1132
|
+
# Routed via the standard path-proxy (``tables.set_cell`` →
|
|
1133
|
+
# ``TableSetCell`` per ``_OP_TO_COMMAND``) so test fakes
|
|
1134
|
+
# that intercept at the namespace level see the call the
|
|
1135
|
+
# same way they see every other op.
|
|
1095
1136
|
run_sync(
|
|
1096
|
-
session.doc.
|
|
1137
|
+
session.doc.tables.set_cell(
|
|
1097
1138
|
{
|
|
1098
|
-
"
|
|
1099
|
-
"
|
|
1139
|
+
"tableNodeId": self._table._node_id,
|
|
1140
|
+
"rowIndex": self._row,
|
|
1141
|
+
"columnIndex": self._col,
|
|
1100
1142
|
"content": fragment,
|
|
1101
1143
|
},
|
|
1102
1144
|
),
|
|
@@ -1105,7 +1147,7 @@ class _Cell:
|
|
|
1105
1147
|
except Exception as e:
|
|
1106
1148
|
raise RuntimeError(
|
|
1107
1149
|
f"Failed to set _Cell.text on cell ({self._row}, {self._col}) "
|
|
1108
|
-
f"of table {self._table.
|
|
1150
|
+
f"of table {self._table._node_id}: {e!r}",
|
|
1109
1151
|
) from e
|
|
1110
1152
|
|
|
1111
1153
|
@property
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "athena-python-docx"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.10.0"
|
|
8
8
|
description = "Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|