athena-python-docx 0.6.2__tar.gz → 0.8.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.6.2 → athena_python_docx-0.8.0}/CLAUDE.md +46 -5
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/PKG-INFO +1 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_buffer.py +66 -106
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_http_doc.py +60 -5
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/commands.py +47 -15
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/document.py +73 -200
- athena_python_docx-0.8.0/docx/errors.py +88 -0
- athena_python_docx-0.8.0/docx/oxml/__init__.py +148 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/settings.py +20 -20
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/table.py +90 -19
- athena_python_docx-0.8.0/docx/text/hyperlink.py +167 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/paragraph.py +122 -21
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/pyproject.toml +1 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/fake_session.py +9 -4
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -6
- athena_python_docx-0.8.0/tests/fidelity/op_snapshots/17_table_basic.json +4 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -6
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +2 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/23_nested_table.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/35_full_report.json +12 -10
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -100
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -4
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -13
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +2 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +3 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +800 -401
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -19
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -3
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -30
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +18 -10
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -10
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -100
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -4
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -50
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -2
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +90 -66
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +240 -81
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -1
- athena_python_docx-0.8.0/tests/fidelity/op_snapshots/ex14_styled_report_table.json +211 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +120 -90
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +18 -15
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +18 -19
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +28 -23
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +32 -21
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +40 -31
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +8 -7
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +64 -32
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -12
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -13
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -8
- athena_python_docx-0.6.2/tests/fidelity/op_snapshots/ex14_styled_report_table.json → athena_python_docx-0.8.0/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +58 -47
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -2
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/ours_spec.json +1822 -289
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/parity_crawl.py +26 -3
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/parity_diff.json +87 -185
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/stock_spec.json +16 -16
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/test_e2e_against_staging.py +1 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/baseline_gaps.json +1 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/compare.py +16 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/reports/GAP_ANALYSIS.md +29 -5
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/reports/gap_report.json +1671 -12
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/snapshots/athena_latest.json +622 -1052
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_batching_perf.py +96 -126
- athena_python_docx-0.8.0/tests/test_block_not_found_error.py +246 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_buffer.py +30 -13
- athena_python_docx-0.8.0/tests/test_cell_text_plain_fastpath.py +60 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_command_dataclasses.py +10 -1
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_commands.py +12 -2
- athena_python_docx-0.8.0/tests/test_hyperlink_coalescing.py +199 -0
- athena_python_docx-0.8.0/tests/test_insert_deferred.py +138 -0
- athena_python_docx-0.8.0/tests/test_oxml_shim.py +123 -0
- athena_python_docx-0.8.0/tests/test_silent_stub_settings.py +75 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_wire_contract.py +5 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/uv.lock +1 -1
- athena_python_docx-0.6.2/docx/errors.py +0 -45
- athena_python_docx-0.6.2/docx/text/hyperlink.py +0 -123
- athena_python_docx-0.6.2/tests/fidelity/op_snapshots/17_table_basic.json +0 -5
- athena_python_docx-0.6.2/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -181
- athena_python_docx-0.6.2/tests/test_silent_stub_settings.py +0 -68
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/.gitignore +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/README.md +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_http.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/api.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/client.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/comments.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/section.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/shape.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/shared.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/run.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/docx/typing.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/scripts/publish.sh +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/fidelity/runner.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.6.2 → athena_python_docx-0.8.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -39,6 +39,18 @@ These standard python-docx members don't apply to a Superdoc-backed SDK:
|
|
|
39
39
|
`Comment.tables` — SuperDoc models a comment as a single text body,
|
|
40
40
|
not a `BlockItemContainer`. Use `Comment.text` instead. The
|
|
41
41
|
paragraph/table-bearing surface raises `CommentsNotImplementedError`.
|
|
42
|
+
- **`docx.oxml.*`** — the entire raw-OOXML module tree (``ns.qn``,
|
|
43
|
+
``OxmlElement``, ``CT_*`` classes, etc.) is unavailable because the
|
|
44
|
+
SDK is HTTP-only against a SuperDoc Y.Doc; there is no local lxml
|
|
45
|
+
tree to manipulate. As of 0.8.0, ``docx.oxml`` is a real stub
|
|
46
|
+
package that raises a typed
|
|
47
|
+
:class:`docx.oxml.OxmlNotAvailableError` (subclass of
|
|
48
|
+
``ImportError``) on any attribute access, with an inline pointer at
|
|
49
|
+
the high-level API (``Document.add_paragraph``, ``Run.bold``,
|
|
50
|
+
``_Cell.text``, …) or the typed command surface in
|
|
51
|
+
``docx.commands``. Pre-0.8.0 this used to fail with the stdlib's
|
|
52
|
+
generic ``ModuleNotFoundError: No module named 'docx.oxml'`` and
|
|
53
|
+
agents had to retry to discover the gap.
|
|
42
54
|
|
|
43
55
|
### Phase-3b upstream-blocked surface
|
|
44
56
|
|
|
@@ -135,11 +147,40 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
|
|
|
135
147
|
backoff, 429/502/503/504). The legacy `transport="direct"` (embedded
|
|
136
148
|
Superdoc CLI + y-websocket from Python) was removed in 0.5.0; agent
|
|
137
149
|
pods no longer embed Superdoc.
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
- **Transparent batching (0.7.0+):** Create* commands
|
|
151
|
+
(`CreateParagraph`, `CreateHeading`, `CreateTable`, `CreateImage`)
|
|
152
|
+
ALWAYS pre-mint a client-side UUID (`client_node_id`) and defer
|
|
153
|
+
through the buffer. The applier resolves UUIDs to real SuperDoc
|
|
154
|
+
ids via per-batch `clientIdMap` on flush, and the buffer rewrites
|
|
155
|
+
each proxy's `_node_id` in-place. Net result: 30 `add_paragraph`
|
|
156
|
+
calls = 1 HTTP request, with no explicit `batch()` context manager
|
|
157
|
+
in the public API (1:1 python-docx parity).
|
|
158
|
+
- Flush triggers: queries (`BlocksList`, `Find`, `GetNodeById`, …)
|
|
159
|
+
drain pending ops before running; the 100 ms idle timer fires on
|
|
160
|
+
inactivity so collab updates stream live; `Document.save()` and
|
|
161
|
+
the context-manager exit drain explicitly; `docx.flush_all()` is
|
|
162
|
+
the Daytona-prelude hook that flushes every live buffer in the
|
|
163
|
+
process.
|
|
164
|
+
- **Insert deferral (0.8.0+):** `Insert` was removed from the
|
|
165
|
+
response-bearing set because every in-tree caller
|
|
166
|
+
(`Paragraph._insert_run_text_segments`, `Run.add_text`, `_Cell.text`)
|
|
167
|
+
ignores the response — the Run proxy wraps a known client-side range
|
|
168
|
+
and doesn't need the server's echoed node id. Net result: a styled
|
|
169
|
+
run (one `add_run` + 6 format setters) ships as 1 HTTP request
|
|
170
|
+
instead of 2. The remaining response-bearing ops without a client id
|
|
171
|
+
(`ListsCreate`, `ListsAttach`, `CommentsCreate`, `CommentsPatch`,
|
|
172
|
+
`TrackChangesDecide`) keep their eager-flush semantics so callers
|
|
173
|
+
reading back ids still see real data. A `Document.add_paragraph`
|
|
174
|
+
with `style="List Bullet"` flushes the queued CreateParagraph in
|
|
175
|
+
the same batch as the follow-up `ListsCreate` — still one HTTP
|
|
176
|
+
request per logical operation.
|
|
177
|
+
- **Plain-text cell fast path (0.8.0+):** `_Cell.text = value` skips
|
|
178
|
+
the eager `doc.markdownToFragment` query when ``value`` contains no
|
|
179
|
+
markdown control characters (the dominant case for tabular data —
|
|
180
|
+
numbers, labels, currency strings). The fragment is built locally
|
|
181
|
+
and the follow-up `doc.insert` is buffered, so plain cell
|
|
182
|
+
assignments are 0 HTTP requests until the next flush. See
|
|
183
|
+
``docx.table._is_plain_text`` for the trigger predicate.
|
|
143
184
|
- The path-proxy in `_http_doc.py` is an internal translation layer:
|
|
144
185
|
call sites that look like `await self._session.doc.create.paragraph(p)`
|
|
145
186
|
resolve to `CommandBuffer.call(CreateParagraph(**p))`. Rewriting call
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.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>
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"""HTTP command buffer for the docx-studio SDK.
|
|
2
2
|
|
|
3
3
|
The buffer sits between SDK call sites and the HTTP transport. Every SDK
|
|
4
|
-
mutation routes through it; we flush eagerly for queries and
|
|
5
|
-
ops
|
|
6
|
-
one HTTP request instead of N.
|
|
4
|
+
mutation routes through it; we flush eagerly for queries, and idle-batch
|
|
5
|
+
all other ops — including Create* — so a burst of ``add_paragraph`` calls
|
|
6
|
+
ships as one HTTP request instead of N.
|
|
7
|
+
|
|
8
|
+
Create* commands are deferred because the SDK pre-mints a client-side
|
|
9
|
+
UUID for every new node (see ``Document._mint_client_node_id``). The
|
|
10
|
+
proxy returned to the caller is stamped with that UUID; the applier
|
|
11
|
+
resolves UUIDs to real SuperDoc ids via ``clientIdMap`` and echoes the
|
|
12
|
+
mapping back, at which point the buffer rewrites each proxy's
|
|
13
|
+
``_node_id``. This makes batching invisible at the call site — user
|
|
14
|
+
code looks like python-docx, runs at python-docx-batched speed.
|
|
7
15
|
|
|
8
16
|
Concurrency model: the SDK serializes calls through ``_batching.run_sync``
|
|
9
17
|
(one persistent event-loop thread), so the buffer's primary thread is the
|
|
@@ -23,11 +31,10 @@ from __future__ import annotations
|
|
|
23
31
|
import sys
|
|
24
32
|
import threading
|
|
25
33
|
import weakref
|
|
26
|
-
from
|
|
27
|
-
from typing import TYPE_CHECKING, Any, Generator
|
|
34
|
+
from typing import TYPE_CHECKING, Any
|
|
28
35
|
|
|
29
36
|
from docx import _ptc
|
|
30
|
-
from docx.commands import Command, must_flush_immediately
|
|
37
|
+
from docx.commands import Command, is_response_bearing, must_flush_immediately
|
|
31
38
|
|
|
32
39
|
if TYPE_CHECKING:
|
|
33
40
|
from docx._http_doc import HttpClient
|
|
@@ -125,12 +132,17 @@ class CommandBuffer:
|
|
|
125
132
|
"""Buffers commands for one Document/asset.
|
|
126
133
|
|
|
127
134
|
Behaviour:
|
|
128
|
-
- Queries
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
- Queries (BlocksList, Find, GetNodeById, …) flush immediately and
|
|
136
|
+
drain any pending mutations in the same batch so ordering is preserved.
|
|
137
|
+
- Every other op — formatters, setters, AND Create* — queues. The idle
|
|
138
|
+
timer flushes after :data:`DEFAULT_AUTO_FLUSH_SECONDS` of inactivity,
|
|
139
|
+
the next eager (query) call drains, or explicit ``flush()`` drains.
|
|
140
|
+
|
|
141
|
+
Create* commands defer because the SDK pre-mints a client-side UUID
|
|
142
|
+
(``client_node_id`` / ``client_entity_id``); the applier translates
|
|
143
|
+
the UUID to a real SuperDoc id in a per-batch ``clientIdMap`` and
|
|
144
|
+
echoes the mapping back so the SDK can rewrite each proxy's
|
|
145
|
+
``_node_id`` on flush.
|
|
134
146
|
"""
|
|
135
147
|
|
|
136
148
|
def __init__(
|
|
@@ -154,11 +166,6 @@ class CommandBuffer:
|
|
|
154
166
|
# original semantics.
|
|
155
167
|
self._change_mode: str | None = None
|
|
156
168
|
self._user: dict[str, str] | None = None
|
|
157
|
-
# Batch mode flag — when True, Create* commands buffer instead
|
|
158
|
-
# of flushing immediately, and proxies bind to a client-side
|
|
159
|
-
# UUID instead of waiting for the server response. See
|
|
160
|
-
# :meth:`Document.batch` and ``PERFORMANCE_BATCHING_ANALYSIS.md``.
|
|
161
|
-
self._batch_depth: int = 0
|
|
162
169
|
# client_node_id → list of (proxy, attr) pairs to update with the
|
|
163
170
|
# real nodeId after flush. Populated by ``add_paragraph`` /
|
|
164
171
|
# ``add_heading`` / etc. when they queue a Create with a
|
|
@@ -168,22 +175,11 @@ class CommandBuffer:
|
|
|
168
175
|
] = {}
|
|
169
176
|
_register(self)
|
|
170
177
|
|
|
171
|
-
@property
|
|
172
|
-
def is_batching(self) -> bool:
|
|
173
|
-
"""``True`` if a ``with doc.batch():`` block is currently open.
|
|
174
|
-
|
|
175
|
-
SDK call sites read this to decide whether to defer Create*
|
|
176
|
-
commands or eager-flush them. Reentrant — nested ``batch()``
|
|
177
|
-
blocks increment the counter and decrement on exit; the outer
|
|
178
|
-
block is what actually flushes.
|
|
179
|
-
"""
|
|
180
|
-
return self._batch_depth > 0
|
|
181
|
-
|
|
182
178
|
def register_proxy_id_ref(
|
|
183
179
|
self, client_id: str, proxy: object, attr: str = "_node_id"
|
|
184
180
|
) -> None:
|
|
185
181
|
"""Register that ``proxy.<attr>`` should be rewritten from
|
|
186
|
-
``client_id`` to the real node id once the
|
|
182
|
+
``client_id`` to the real node id once the queue flushes.
|
|
187
183
|
|
|
188
184
|
Called by ``Document.add_paragraph`` (and equivalents) when they
|
|
189
185
|
queue a Create with a ``client_node_id``. The flush loop walks
|
|
@@ -254,21 +250,19 @@ class CommandBuffer:
|
|
|
254
250
|
def call(self, cmd: Command) -> Any:
|
|
255
251
|
"""Execute or buffer ``cmd``.
|
|
256
252
|
|
|
257
|
-
For
|
|
258
|
-
|
|
259
|
-
the
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
proxy
|
|
270
|
-
applier's ``real_node_id`` / ``real_entity_id`` echo lets the
|
|
271
|
-
SDK rewrite the proxy in-place.
|
|
253
|
+
For queries (``BlocksList``, ``Find``, ``GetNodeById``, …)
|
|
254
|
+
AND response-bearing commands that don't carry a client-side
|
|
255
|
+
id, drains the pending queue and runs ``cmd`` in the same
|
|
256
|
+
batch; returns the per-cmd result dict.
|
|
257
|
+
|
|
258
|
+
Otherwise — pure mutations (formatters, setters) AND Create*
|
|
259
|
+
commands that carry a pre-minted ``client_node_id`` /
|
|
260
|
+
``client_entity_id`` — appends to the queue, resets the idle
|
|
261
|
+
timer, and returns ``None``. Caller MUST NOT rely on the return
|
|
262
|
+
value of a buffered mutation. For deferred Creates, the
|
|
263
|
+
applier resolves the client UUID to a real SuperDoc id via
|
|
264
|
+
``clientIdMap`` on flush and the buffer rewrites each registered
|
|
265
|
+
proxy's ``_node_id`` in-place.
|
|
272
266
|
"""
|
|
273
267
|
if self._closed:
|
|
274
268
|
raise RuntimeError(
|
|
@@ -286,7 +280,7 @@ class CommandBuffer:
|
|
|
286
280
|
except Exception: # noqa: BLE001
|
|
287
281
|
pass
|
|
288
282
|
|
|
289
|
-
if must_flush_immediately(cmd) and not self.
|
|
283
|
+
if must_flush_immediately(cmd) and not self._has_client_id(cmd):
|
|
290
284
|
return self._eager_flush_with(cmd)
|
|
291
285
|
|
|
292
286
|
with self._lock:
|
|
@@ -294,23 +288,25 @@ class CommandBuffer:
|
|
|
294
288
|
self._reset_timer_locked()
|
|
295
289
|
return None
|
|
296
290
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
291
|
+
@staticmethod
|
|
292
|
+
def _has_client_id(cmd: Command) -> bool:
|
|
293
|
+
"""Return ``True`` iff this command carries a pre-minted
|
|
294
|
+
client-side id (``client_node_id`` for nodes,
|
|
295
|
+
``client_entity_id`` for comments).
|
|
296
|
+
|
|
297
|
+
Used by :meth:`call` to decide whether a response-bearing
|
|
298
|
+
Create can defer. Pure response-bearing ops without a client
|
|
299
|
+
id (``Insert``, ``CommentsPatch``, ``TrackChangesDecide``,
|
|
300
|
+
legacy callers) keep their eager-flush semantics so callers
|
|
301
|
+
that read the response still see real data.
|
|
308
302
|
"""
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
303
|
+
return (
|
|
304
|
+
is_response_bearing(cmd)
|
|
305
|
+
and (
|
|
306
|
+
getattr(cmd, "client_node_id", None) is not None
|
|
307
|
+
or getattr(cmd, "client_entity_id", None) is not None
|
|
308
|
+
)
|
|
309
|
+
)
|
|
314
310
|
|
|
315
311
|
def flush(self) -> list[Any]:
|
|
316
312
|
"""Flush pending commands as one HTTP batch.
|
|
@@ -321,9 +317,10 @@ class CommandBuffer:
|
|
|
321
317
|
After the batch returns, walks per-cmd results for
|
|
322
318
|
``real_node_id`` / ``real_entity_id`` echoes and updates any
|
|
323
319
|
proxies registered via :meth:`register_proxy_id_ref` with the
|
|
324
|
-
resolved server ids. This
|
|
325
|
-
|
|
326
|
-
real ids
|
|
320
|
+
resolved server ids. This completes the round-trip for the
|
|
321
|
+
always-on transparent batching path — the SDK's caller-facing
|
|
322
|
+
proxies pick up real ids without the caller ever seeing the
|
|
323
|
+
UUID swap.
|
|
327
324
|
"""
|
|
328
325
|
with self._lock:
|
|
329
326
|
self._cancel_timer_locked()
|
|
@@ -375,43 +372,6 @@ class CommandBuffer:
|
|
|
375
372
|
pass
|
|
376
373
|
return results
|
|
377
374
|
|
|
378
|
-
@contextmanager
|
|
379
|
-
def batch(self) -> Generator[None, None, None]:
|
|
380
|
-
"""Group calls into one HTTP batch.
|
|
381
|
-
|
|
382
|
-
Inside the ``with`` block:
|
|
383
|
-
|
|
384
|
-
- Queries (``BlocksList``, ``Find``, ``GetNodeById``, …) still
|
|
385
|
-
eager-flush — the caller is awaiting their result, so we have
|
|
386
|
-
no choice.
|
|
387
|
-
- Pure mutations (formatters, setters) accumulate without their
|
|
388
|
-
idle timer firing.
|
|
389
|
-
- Create*-shape commands that carry a ``client_node_id`` /
|
|
390
|
-
``client_entity_id`` (set by ``Document.add_paragraph`` and
|
|
391
|
-
friends when they detect batch mode) also accumulate — the
|
|
392
|
-
server resolves the client UUIDs to real SuperDoc ids in a
|
|
393
|
-
single batch via the per-request ``clientIdMap``.
|
|
394
|
-
|
|
395
|
-
On exit, drains anything left. Reentrant: nested ``batch()``
|
|
396
|
-
blocks share the same accumulating queue; only the outermost
|
|
397
|
-
block flushes.
|
|
398
|
-
"""
|
|
399
|
-
with self._lock:
|
|
400
|
-
self._cancel_timer_locked()
|
|
401
|
-
old_window = self._auto_flush_seconds
|
|
402
|
-
self._auto_flush_seconds = 0.0 # disable timer-scheduled flush
|
|
403
|
-
self._batch_depth += 1
|
|
404
|
-
try:
|
|
405
|
-
yield
|
|
406
|
-
finally:
|
|
407
|
-
with self._lock:
|
|
408
|
-
self._batch_depth -= 1
|
|
409
|
-
outermost = self._batch_depth == 0
|
|
410
|
-
if outermost:
|
|
411
|
-
self._auto_flush_seconds = old_window
|
|
412
|
-
if outermost:
|
|
413
|
-
self.flush()
|
|
414
|
-
|
|
415
375
|
def close(self) -> None:
|
|
416
376
|
"""Flush and disable. Idempotent."""
|
|
417
377
|
if self._closed:
|
|
@@ -427,11 +387,11 @@ class CommandBuffer:
|
|
|
427
387
|
def _eager_flush_with(self, cmd: Command) -> Any:
|
|
428
388
|
"""Drain pending + run ``cmd`` in one batch; return cmd's result.
|
|
429
389
|
|
|
430
|
-
When pending commands include
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
get their real ids written back via the same flush-time
|
|
434
|
-
that :meth:`flush` does.
|
|
390
|
+
When pending commands include Creates with registered proxy
|
|
391
|
+
refs (queries mid-stream cause this — the caller is awaiting
|
|
392
|
+
their result and the queue must drain first), the proxies
|
|
393
|
+
still get their real ids written back via the same flush-time
|
|
394
|
+
rewrite that :meth:`flush` does.
|
|
435
395
|
"""
|
|
436
396
|
with self._lock:
|
|
437
397
|
self._cancel_timer_locked()
|
|
@@ -93,6 +93,7 @@ from docx.commands import (
|
|
|
93
93
|
SetSectionPageMargins,
|
|
94
94
|
SetSectionPageSetup,
|
|
95
95
|
SetSectionTitlePage,
|
|
96
|
+
SetSectionsOddEvenHeadersFooters,
|
|
96
97
|
TablesGet,
|
|
97
98
|
TablesGetCells,
|
|
98
99
|
TablesGetProperties,
|
|
@@ -111,6 +112,7 @@ from docx.commands import (
|
|
|
111
112
|
)
|
|
112
113
|
from docx.errors import (
|
|
113
114
|
AuthenticationError,
|
|
115
|
+
BlockNotFoundError,
|
|
114
116
|
DocxError,
|
|
115
117
|
NotFoundError,
|
|
116
118
|
SessionError,
|
|
@@ -133,6 +135,39 @@ _NOT_FOUND_ERROR_NAMES: frozenset[str] = frozenset(
|
|
|
133
135
|
)
|
|
134
136
|
|
|
135
137
|
|
|
138
|
+
def _looks_like_block_not_found(err_obj: dict) -> bool:
|
|
139
|
+
"""Detect SuperDoc's ``Block "<type>:<id>" was not found`` shape.
|
|
140
|
+
|
|
141
|
+
Triggers the typed :class:`BlockNotFoundError` so agent code can
|
|
142
|
+
distinguish a missing-block miss (cell-inner-paragraph addressing
|
|
143
|
+
bug, stale id from a different session) from a generic transport
|
|
144
|
+
or validation error.
|
|
145
|
+
"""
|
|
146
|
+
msg = err_obj.get("message")
|
|
147
|
+
if not isinstance(msg, str):
|
|
148
|
+
return False
|
|
149
|
+
lower = msg.lower()
|
|
150
|
+
if "not found" not in lower:
|
|
151
|
+
return False
|
|
152
|
+
# Be conservative: require either ``block "`` (the SuperDoc CLI's
|
|
153
|
+
# quoted-id format) or ``block <id>`` followed by ``not found``.
|
|
154
|
+
return 'block "' in lower or ('block ' in lower and ' was not found' in lower)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
_CELL_PARAGRAPH_HINT: str = (
|
|
158
|
+
"\n\nHint: SuperDoc 1.8.1 cannot format paragraphs nested inside "
|
|
159
|
+
"table cells via SetParagraphAlignment / SetParagraphStyle / "
|
|
160
|
+
"SetParagraphIndentation / SetParagraphSpacing or doc.insert with "
|
|
161
|
+
"a paragraph-block target. The cell's inner paragraph id is "
|
|
162
|
+
"returned by cell.getNodeById but isn't a top-level addressable "
|
|
163
|
+
"block. Materialize the cell's paragraph first via "
|
|
164
|
+
'``cell.text = "value"``, then re-read ``cell.paragraphs[0]`` and '
|
|
165
|
+
"apply format ops to that post-materialization Paragraph proxy. "
|
|
166
|
+
"Tracked upstream at docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md "
|
|
167
|
+
"§ 'cell-inner paragraph addressing'."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
136
171
|
def _looks_like_not_found(parsed: dict) -> bool:
|
|
137
172
|
"""Inspect a docx-studio partial-failure dict and decide whether it
|
|
138
173
|
describes a "no such entity" miss (vs. a real transport / validation
|
|
@@ -284,11 +319,30 @@ def _http_post_json(
|
|
|
284
319
|
# sites (``Comments.get``) can coerce it to ``None`` without
|
|
285
320
|
# swallowing real transport / validation failures.
|
|
286
321
|
err_obj = parsed.get("error") if isinstance(parsed, dict) else None
|
|
287
|
-
if isinstance(err_obj, dict)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
322
|
+
if isinstance(err_obj, dict):
|
|
323
|
+
base_msg = f"docx-studio batch reported a partial failure: {parsed!r}"
|
|
324
|
+
# ``BlockNotFoundError`` is the narrower miss — caller is most
|
|
325
|
+
# likely targeting a cell-inner paragraph or stale-session
|
|
326
|
+
# block id. Surface the typed exception plus an agent-readable
|
|
327
|
+
# workaround so the next attempt doesn't repeat the same
|
|
328
|
+
# mistake. The cell-paragraph hint only applies when the
|
|
329
|
+
# missing id has the ``paragraph:`` prefix (SuperDoc's quoted-
|
|
330
|
+
# id error format) — stale list-item / table-row / image ids
|
|
331
|
+
# would benefit from a different hint or none at all, and a
|
|
332
|
+
# red-herring "use cell.text" pointer would just waste the
|
|
333
|
+
# next retry.
|
|
334
|
+
if _looks_like_block_not_found(err_obj):
|
|
335
|
+
msg_str = err_obj.get("message")
|
|
336
|
+
paragraph_block = (
|
|
337
|
+
isinstance(msg_str, str)
|
|
338
|
+
and "paragraph:" in msg_str.lower()
|
|
339
|
+
)
|
|
340
|
+
raise BlockNotFoundError(
|
|
341
|
+
base_msg + (_CELL_PARAGRAPH_HINT if paragraph_block else ""),
|
|
342
|
+
payload=err_obj,
|
|
343
|
+
)
|
|
344
|
+
if _looks_like_not_found(err_obj):
|
|
345
|
+
raise NotFoundError(base_msg, payload=err_obj)
|
|
292
346
|
raise DocxError(
|
|
293
347
|
f"docx-studio batch reported a partial failure: {parsed!r}",
|
|
294
348
|
)
|
|
@@ -465,6 +519,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
|
|
|
465
519
|
"sections.set_header_footer_margins": SetSectionHeaderFooterMargins,
|
|
466
520
|
"sections.set_break_type": SetSectionBreakType,
|
|
467
521
|
"sections.set_title_page": SetSectionTitlePage,
|
|
522
|
+
"sections.set_odd_even_headers_footers": SetSectionsOddEvenHeadersFooters,
|
|
468
523
|
"sections.set_link_to_previous": SetSectionLinkToPrevious,
|
|
469
524
|
# Tables (mutations)
|
|
470
525
|
"tables.insert_row": TablesInsertRow,
|
|
@@ -59,17 +59,19 @@ class Command:
|
|
|
59
59
|
|
|
60
60
|
# --- Create* commands carry an optional client-assigned node id ---
|
|
61
61
|
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# applier
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
62
|
+
# The SDK pre-generates a UUID for every new Paragraph/Heading/Table/
|
|
63
|
+
# Image and stamps the proxy with it. The applier translates
|
|
64
|
+
# ``client_node_id`` → real SuperDoc nodeId in a per-batch map (see
|
|
65
|
+
# ``apps/api/src/commands/applier.ts``), so subsequent commands in the
|
|
66
|
+
# same batch can target the new block by its client-side id before the
|
|
67
|
+
# response has even returned. After flush, the buffer reads the
|
|
68
|
+
# resolved ``real_node_id`` out of each Create's response and updates
|
|
69
|
+
# the proxy in-place.
|
|
70
|
+
#
|
|
71
|
+
# Direct internal callers that bypass ``Document`` (legacy helpers,
|
|
72
|
+
# fidelity tests) may leave the field unset; the buffer then eager-
|
|
73
|
+
# flushes the Create immediately so callers that read the response
|
|
74
|
+
# still see real data.
|
|
73
75
|
#
|
|
74
76
|
# The field is ``client_node_id`` on the Python side and arrives at
|
|
75
77
|
# the server as ``clientNodeId`` via ``_snake_to_camel`` — matches the
|
|
@@ -283,6 +285,23 @@ class SetSectionTitlePage(Command):
|
|
|
283
285
|
enabled: bool
|
|
284
286
|
|
|
285
287
|
|
|
288
|
+
@dataclass
|
|
289
|
+
class SetSectionsOddEvenHeadersFooters(Command):
|
|
290
|
+
"""Toggle the document-level ``<w:evenAndOddHeaders/>`` setting.
|
|
291
|
+
|
|
292
|
+
Despite living under the ``sections.*`` namespace on the SuperDoc
|
|
293
|
+
bound-doc API, this op carries no ``target`` — it sets a single
|
|
294
|
+
doc-level flag that applies to every section. Word stores the
|
|
295
|
+
underlying value on ``word/settings.xml`` as
|
|
296
|
+
``<w:evenAndOddHeaders/>``, which is what python-docx's
|
|
297
|
+
``Settings.odd_and_even_pages_header_footer`` writes to.
|
|
298
|
+
|
|
299
|
+
Available since SuperDoc 1.8.1 (``DocSectionsSetOddEvenHeadersFooters``).
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
enabled: bool
|
|
303
|
+
|
|
304
|
+
|
|
286
305
|
@dataclass
|
|
287
306
|
class SetSectionLinkToPrevious(Command):
|
|
288
307
|
"""Toggle the section-side ``linked-to-previous`` flag for one
|
|
@@ -532,8 +551,13 @@ class CommentsCreate(Command):
|
|
|
532
551
|
text: str | None = None
|
|
533
552
|
target: dict[str, Any] | None = None
|
|
534
553
|
parent_id: str | None = None
|
|
535
|
-
# Optional client-assigned entity id for
|
|
536
|
-
#
|
|
554
|
+
# Optional client-assigned entity id for transparent-batched
|
|
555
|
+
# CommentsCreate (parallel to ``client_node_id`` on Create*; the
|
|
556
|
+
# server applier resolves UUIDs via the same per-batch
|
|
557
|
+
# ``clientIdMap``). ``Comments.add_comment`` currently leaves this
|
|
558
|
+
# unset, so CommentsCreate eager-flushes — left in place for
|
|
559
|
+
# future callers that want to defer comment creates alongside
|
|
560
|
+
# other ops.
|
|
537
561
|
client_entity_id: str | None = None
|
|
538
562
|
|
|
539
563
|
|
|
@@ -790,8 +814,15 @@ _RESPONSE_BEARING_TYPES: frozenset[str] = frozenset(
|
|
|
790
814
|
# CreateImage returns {image: {nodeId}}; SetImageSize and the
|
|
791
815
|
# InlineShape proxy both need that nodeId, so it must flush.
|
|
792
816
|
"CreateImage",
|
|
793
|
-
# Insert
|
|
794
|
-
|
|
817
|
+
# Insert is INTENTIONALLY not here as of 0.8.0. All in-tree
|
|
818
|
+
# callers (``Paragraph._insert_run_text_segments``, ``Run.add_text``,
|
|
819
|
+
# ``_Cell.text``) wrap a known client-side range/cell target and
|
|
820
|
+
# never read Insert's response; deferring it lets a styled
|
|
821
|
+
# ``add_run`` flow ship its text-insert in the same HTTP batch
|
|
822
|
+
# as the format setters that follow it. If a future caller needs
|
|
823
|
+
# the Insert response, route it through ``CommandBuffer._eager_flush_with``
|
|
824
|
+
# at the call site rather than re-adding Insert here, so the
|
|
825
|
+
# batched path isn't penalized for the one outlier.
|
|
795
826
|
# CreateSectionBreak intentionally NOT here — it returns no node id;
|
|
796
827
|
# the caller resolves the new section via sections.list afterwards.
|
|
797
828
|
# CommentsCreate returns the new comment's entityId — caller wraps
|
|
@@ -856,6 +887,7 @@ __all__ = [
|
|
|
856
887
|
"SetSectionHeaderFooterMargins",
|
|
857
888
|
"SetSectionBreakType",
|
|
858
889
|
"SetSectionTitlePage",
|
|
890
|
+
"SetSectionsOddEvenHeadersFooters",
|
|
859
891
|
"SetSectionLinkToPrevious",
|
|
860
892
|
# Tables (mutations)
|
|
861
893
|
"TablesInsertRow",
|