athena-python-docx 0.21.0__tar.gz → 0.21.2__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.21.0 → athena_python_docx-0.21.2}/CLAUDE.md +88 -57
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/PKG-INFO +1 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/__init__.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_buffer.py +5 -5
- athena_python_docx-0.21.2/docx/_citations.py +154 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_http_doc.py +32 -24
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_image_utils.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_postproc.py +48 -48
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_references.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_timeouts.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/bookmarks.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/charts.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/client.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/commands.py +61 -61
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/comments.py +23 -23
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/document.py +57 -54
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/section.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/table.py +5 -5
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/text.py +22 -22
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/errors.py +11 -11
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/footnotes.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/math.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/opc/coreprops.py +5 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/oxml/__init__.py +5 -5
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/revisions.py +14 -14
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/sdt.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/section.py +80 -80
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/settings.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/shape.py +8 -8
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/styles/style.py +31 -33
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/styles/styles.py +11 -11
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/table.py +128 -91
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/hyperlink.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/pagebreak.py +9 -9
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/paragraph.py +49 -46
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/parfmt.py +12 -12
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/run.py +32 -33
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/tabstops.py +15 -15
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/typing.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/pyproject.toml +1 -7
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/docx_exec_lab_server.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/dump_wire_fixtures.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/round_trip_smoke.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/smoke_test_block_not_found.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/conftest.py +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/__init__.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/ab_probe_cases.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/ab_probe_runner.py +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/binary_round_trip.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/cases.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/complex_cases.py +5 -5
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/extract.py +5 -5
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/extreme_cases.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/fake_session.py +12 -12
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/README.md +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/_runner.py +12 -11
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/extractor.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/test_pw_corpus.py +13 -25
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/test_pw_research_digest.py +10 -10
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshot.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/ours_spec.json +7 -7
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/real_world_cases.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/test_e2e_against_staging.py +20 -107
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/intentional_deviations.json +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/snapshots/athena_latest.json +12 -12
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_add_section_extract_items.py +5 -5
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_batching_perf.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_block_not_found_error.py +12 -12
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_add_paragraph_wire_shape.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_add_table_not_supported.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_inner_add_run_via_cell_insert.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_inner_format_stash.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_inner_run_guard.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_text_plain_fastpath.py +1 -1
- athena_python_docx-0.21.2/tests/test_citations.py +317 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_collapsed_range_format.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_commands.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_comments.py +4 -4
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_document_clear.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_e2e_partial_failure_cascade.py +8 -8
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_http_transport.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_hyperlink_coalescing.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_list_styles.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_merged_cell_secondary_slot.py +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_merged_cells.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_parity_misc.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_parity_round2.py +10 -10
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_partial_failure_cascade.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_phase_a_behavior.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_phase_b_headers_footers.py +10 -10
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_phase_c_tables.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_positional_cell_id.py +112 -7
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_postproc_cell_format_rewrite.py +7 -7
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_postproc_ref_restore.py +8 -8
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_pr19766_review_fixes.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_python_docx_api_parity.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_revisions.py +13 -13
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_add_paragraph_style.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_cell_add_paragraph.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_comments_add_comment.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_comments_get.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_document_audit.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_enum_section.py +8 -8
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_header_footer.py +7 -7
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_hyperlink.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_inline_shape.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_misc.py +20 -20
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_paragraph_strict.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_paragraph_style_strict.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_parfmt.py +18 -18
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_row_col_cell.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_style.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_style_strict.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_text.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_underline.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_section_audit.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_section_dimensions.py +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_section_onoff.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_settings.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_style.py +6 -6
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_styles.py +10 -10
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_table_dimensions.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_table_layout.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_style_font.py +3 -3
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_style_setters_contract.py +10 -11
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_table_set_cell_perf.py +1 -1
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_wire_contract.py +12 -12
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_zod_wire_contract.py +2 -2
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/uv.lock +2 -114
- athena_python_docx-0.21.0/docx/_citations.py +0 -74
- athena_python_docx-0.21.0/tests/test_citations.py +0 -151
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/.gitignore +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/README.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_batching.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_execution.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_http.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_ptc.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/api.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/enum/style.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/exceptions.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/fields.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/session.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/shared.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/text/font.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/docx/toc.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/publish.sh +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/release.sh +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/README.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.21.0 → athena_python_docx-0.21.2}/tests/test_xml_attr_guard.py +0 -0
|
@@ -25,35 +25,35 @@ Before adding or modifying any API surface:
|
|
|
25
25
|
|
|
26
26
|
Run `uv run pytest tests/test_python_docx_api_parity.py -v -s` to verify parity.
|
|
27
27
|
|
|
28
|
-
### Intentionally omitted (
|
|
28
|
+
### Intentionally omitted (current SDK limitations)
|
|
29
29
|
|
|
30
|
-
These standard python-docx members don't apply to a
|
|
30
|
+
These standard python-docx members don't apply to a DOCX Studio-backed SDK:
|
|
31
31
|
|
|
32
32
|
- `Paragraph._p`, `Run._r` — XML element access (no local XML)
|
|
33
33
|
- `Document.part`, `Paragraph.part`, `Run.part` — package part access
|
|
34
34
|
- `Document.core_properties.last_modified_by` — we use Keryx attribution instead
|
|
35
|
-
- `Document.settings` — Word app settings (not surfaced by
|
|
36
|
-
- `InlineShape.chart` — charts
|
|
35
|
+
- `Document.settings` — Word app settings (not surfaced by DOCX Studio)
|
|
36
|
+
- `InlineShape.chart` — charts are not currently surfaced by the SDK.
|
|
37
37
|
- `Comment.add_paragraph` / `Comment.add_table` /
|
|
38
38
|
`Comment.iter_inner_content` / `Comment.paragraphs` /
|
|
39
|
-
`Comment.tables` —
|
|
39
|
+
`Comment.tables` — DOCX Studio 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
42
|
- **`_Cell.add_table(rows, cols)`** — surface preserved for parity
|
|
43
43
|
(signature matches python-docx, no `width` kwarg) but raises
|
|
44
44
|
:class:`docx.errors.NestedTableNotSupportedError` (subclass of
|
|
45
|
-
`NotImplementedError`) at runtime since 0.11.2.
|
|
46
|
-
no anchor or content-fragment shape
|
|
47
|
-
an existing `tableCell` — `create.table` rejects cell-inner
|
|
45
|
+
`NotImplementedError`) at runtime since 0.11.2. The current
|
|
46
|
+
docx-editor command surface has no anchor or content-fragment shape
|
|
47
|
+
that places a new table inside an existing `tableCell` — `create.table` rejects cell-inner
|
|
48
48
|
paragraph anchors with `INVALID_TARGET`, and the `doc.insert`
|
|
49
49
|
workaround used by `_Cell.add_paragraph` doesn't generalize
|
|
50
50
|
because the apps/api `Insert` schema doesn't yet forward
|
|
51
|
-
`nestingPolicy: {tables: "allow"}` and the
|
|
51
|
+
`nestingPolicy: {tables: "allow"}` and the DOCX editor table-content
|
|
52
52
|
fragment shape isn't documented. Tracked at
|
|
53
|
-
`docx-studio/
|
|
53
|
+
`docx-studio/DOCX_STUDIO_LIMITATIONS.md` § 13.
|
|
54
54
|
- **`docx.oxml.*`** — the entire raw-OOXML module tree (``ns.qn``,
|
|
55
55
|
``OxmlElement``, ``CT_*`` classes, etc.) is unavailable because the
|
|
56
|
-
SDK is HTTP-only against a
|
|
56
|
+
SDK is HTTP-only against a DOCX Studio Y.Doc; there is no local lxml
|
|
57
57
|
tree to manipulate. As of 0.8.0, ``docx.oxml`` is a real stub
|
|
58
58
|
package that raises a typed
|
|
59
59
|
:class:`docx.oxml.OxmlNotAvailableError` (subclass of
|
|
@@ -64,21 +64,21 @@ These standard python-docx members don't apply to a Superdoc-backed SDK:
|
|
|
64
64
|
generic ``ModuleNotFoundError: No module named 'docx.oxml'`` and
|
|
65
65
|
agents had to retry to discover the gap.
|
|
66
66
|
|
|
67
|
-
###
|
|
67
|
+
### Known partially supported surface
|
|
68
68
|
|
|
69
69
|
These are *shipped at the surface* but partially or fully no-op at
|
|
70
|
-
runtime, pending
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
runtime, pending additional docx-editor command support. Behavior should be
|
|
71
|
+
pinned by focused tests and documented in
|
|
72
|
+
`docx-studio/DOCX_STUDIO_LIMITATIONS.md`.
|
|
73
73
|
|
|
74
74
|
- **24 setters on `BaseStyle` / `CharacterStyle` / `ParagraphStyle`**
|
|
75
75
|
(`name`, `style_id`, `hidden`, `locked`, `priority`, `quick_style`,
|
|
76
76
|
`unhide_when_used`, `base_style`, `next_paragraph_style`) emit
|
|
77
77
|
`PendingStyleMutationWarning` and stash on `_overrides`.
|
|
78
|
-
|
|
78
|
+
The current `doc.styles.apply` command surface is constrained to
|
|
79
79
|
`target.scope: "docDefaults"` — no per-style metadata variant.
|
|
80
80
|
Behavior pinned by `tests/test_style_setters_contract.py` (11
|
|
81
|
-
tests); when
|
|
81
|
+
tests); when docx-editor lands a metadata op, those tests will need
|
|
82
82
|
to flip to assert real bus calls.
|
|
83
83
|
- **`Styles.latent_styles`** returns an empty `_LatentStyles` —
|
|
84
84
|
`DocInfoResult.styles` only surfaces `paragraphStyles[]` (a flat
|
|
@@ -119,12 +119,12 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
119
119
|
and silently falls back to ``Normal Table`` (no borders, no
|
|
120
120
|
header fill, no banding). Custom user-defined style names pass
|
|
121
121
|
through unchanged. Whether Word actually renders a Word 2013+
|
|
122
|
-
style after resolution also depends on
|
|
122
|
+
style after resolution also depends on the exported
|
|
123
123
|
``styles.xml`` containing the matching ``<w:style w:type="table">``
|
|
124
|
-
definition
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
definition. If the exported ``styles.xml`` only carries the Word 2007
|
|
125
|
+
set, Word 2013+ styleIds resolve in the ``<w:tblStyle>`` element but
|
|
126
|
+
still fall back to ``Normal Table`` until the export path ships an
|
|
127
|
+
expanded ``styles.xml``.
|
|
128
128
|
|
|
129
129
|
- **`Document.create(name=, base_url=, api_key=, parent_folder_id=, workspace_id=, docx=, agora_base_url=)`**
|
|
130
130
|
classmethod. Stock python-docx returns a blank in-memory document
|
|
@@ -164,14 +164,14 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
164
164
|
When a path or stream IS supplied, the SDK cannot fulfill the
|
|
165
165
|
implied "write bytes to this target" contract, so the call raises
|
|
166
166
|
loudly rather than silently flushing — agents must use Olympus's
|
|
167
|
-
Export DOCX (which goes through the
|
|
167
|
+
Export DOCX (which goes through the DOCX Studio session that already
|
|
168
168
|
has the bytes) instead of expecting a local file.
|
|
169
169
|
|
|
170
170
|
- **`Document.track_revisions: bool`** — when `True`, all subsequent
|
|
171
171
|
mutations are recorded as tracked revisions instead of direct edits.
|
|
172
172
|
python-docx upstream has no top-level toggle (the closest is
|
|
173
173
|
hand-edited `<w:trackChanges/>` on `Document.settings.element`).
|
|
174
|
-
We expose this as a Document-level property because every
|
|
174
|
+
We expose this as a Document-level property because every DOCX Studio
|
|
175
175
|
mutation accepts a per-call `changeMode` envelope field. The
|
|
176
176
|
python-docx-parity alias `Document.settings.track_revisions` reads
|
|
177
177
|
and writes the same flag so call sites that walk `doc.settings`
|
|
@@ -184,10 +184,10 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
184
184
|
because the upstream package has no track-changes API at all.
|
|
185
185
|
|
|
186
186
|
- **`Document.user_name: str | None` / `Document.user_email: str |
|
|
187
|
-
None`** — author identity threaded through to
|
|
187
|
+
None`** — author identity threaded through to DOCX Studio on session-
|
|
188
188
|
open for tracked-change attribution. python-docx's
|
|
189
189
|
`Document.core_properties.last_modified_by` is the closest upstream
|
|
190
|
-
surface; we use the
|
|
190
|
+
surface; we use the DOCX Studio-native fields directly because DOCX Studio
|
|
191
191
|
bakes them into the change records.
|
|
192
192
|
|
|
193
193
|
- **`Document.revisions: Revisions`** — collection of tracked changes
|
|
@@ -195,7 +195,7 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
195
195
|
`accept(id)`, `reject(id)`. Per-revision `Revision.accept()` /
|
|
196
196
|
`Revision.reject()` resolve a single change. python-docx upstream
|
|
197
197
|
has zero track-changes API, so this entire surface is an Athena
|
|
198
|
-
extension wired to
|
|
198
|
+
extension wired to DOCX Studio's `doc.trackChanges.{list,get,decide}`.
|
|
199
199
|
|
|
200
200
|
### Athena extensions for most-requested upstream features (v0.11.0+)
|
|
201
201
|
|
|
@@ -213,7 +213,7 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
213
213
|
tooltip=None) -> Hyperlink`** — appends a hyperlinked run.
|
|
214
214
|
python-docx surfaces `Hyperlink` as read-only; PR #74 has been open
|
|
215
215
|
since 2014 and is the single most-requested missing feature. Routes
|
|
216
|
-
through `CreateHyperlink` (
|
|
216
|
+
through `CreateHyperlink` (DOCX Studio `doc.hyperlinks.create`). Returns
|
|
217
217
|
the same `Hyperlink` class the read path already exposes. Also
|
|
218
218
|
available as `Run.add_hyperlink` for convenience.
|
|
219
219
|
|
|
@@ -293,7 +293,7 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
293
293
|
metadata. python-docx PR #1530 is in flight but unreleased; the
|
|
294
294
|
feature has been requested for years. Routes through
|
|
295
295
|
`SetImageAltText` / `SetImageDecorative` (already wired in
|
|
296
|
-
|
|
296
|
+
DOCX Studio).
|
|
297
297
|
|
|
298
298
|
- **`InlineShape.anchor(*, wrap="square", position_x_pt=,
|
|
299
299
|
position_y_pt=, relative_from_x=, relative_from_y=,
|
|
@@ -370,13 +370,13 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
370
370
|
include_revisions=False) -> bytes`** — render to PDF via the
|
|
371
371
|
Daytona-hosted LibreOffice. python-docx issue #113 was closed as
|
|
372
372
|
wontfix upstream but the request keeps recurring. Routes through
|
|
373
|
-
`ExportPDF` (
|
|
373
|
+
`ExportPDF` (DOCX Studio handles the actual conversion).
|
|
374
374
|
|
|
375
375
|
- **`Document.clear()`** (0.14.0+) — empty the document body so subsequent
|
|
376
376
|
writes start from a clean slate. python-docx has no equivalent (it
|
|
377
377
|
operates on local files where the caller can simply construct a new
|
|
378
378
|
``Document``). Iterates every top-level paragraph and table cell and
|
|
379
|
-
empties their text content. Block structure is preserved (
|
|
379
|
+
empties their text content. Block structure is preserved (DOCX Studio has
|
|
380
380
|
no wire op to delete blocks today), so post-clear the doc holds N
|
|
381
381
|
empty paragraphs rather than collapsing to a single one — for a truly
|
|
382
382
|
empty body, call ``Document.create()`` to mint a fresh asset instead.
|
|
@@ -395,6 +395,27 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
395
395
|
the citation-blue highlight to the destination paragraph/range. It is
|
|
396
396
|
not a live link and does not overwrite destination text.
|
|
397
397
|
|
|
398
|
+
Use citations as evidence, not as generic source mentions.
|
|
399
|
+
``Paragraph.add_citation(...)`` highlights the whole paragraph in Athena, so
|
|
400
|
+
make the destination unit match the evidence: a metric cell/table row for a
|
|
401
|
+
number, one short sentence for a claim, or one short paragraph only when the
|
|
402
|
+
same source supports the full paragraph. If only a few words or numbers in a
|
|
403
|
+
long paragraph are supported, split that claim into its own sentence,
|
|
404
|
+
paragraph, or table row before citing it. Do not add duplicate citations to
|
|
405
|
+
every rendered line when one citation on the semantic claim/table row is
|
|
406
|
+
sufficient.
|
|
407
|
+
Use a mention/reference instead when you only need to point at a related
|
|
408
|
+
source without claiming evidentiary support. For PDFs, prefer a tight page
|
|
409
|
+
text anchor or a page anchor with an ``excerpt`` containing the exact
|
|
410
|
+
phrase/number being supported, not just a broad section title.
|
|
411
|
+
|
|
412
|
+
Prefer a canonical citation string when the source/anchor is already known
|
|
413
|
+
as a Spaces URL, or when the source type is not modeled by the DOCX SDK
|
|
414
|
+
(video/audio time ranges, browser sessions, external URLs, etc.). Typed
|
|
415
|
+
``AssetReference`` + anchor objects are still useful convenience helpers for
|
|
416
|
+
common Athena assets such as spreadsheets and PDFs, but they are not the only
|
|
417
|
+
valid source form.
|
|
418
|
+
|
|
398
419
|
Common agent pattern after writing a supported claim:
|
|
399
420
|
|
|
400
421
|
```python
|
|
@@ -403,6 +424,16 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
403
424
|
|
|
404
425
|
doc = Document("asset_word")
|
|
405
426
|
p = doc.add_paragraph("The combined assessment identified 20,049 total vulnerabilities.")
|
|
427
|
+
|
|
428
|
+
# Preferred generic path: pass a canonical Spaces URL or https URL.
|
|
429
|
+
citation_id = p.add_citation(
|
|
430
|
+
"/dashboard/spaces/?asset_ids=asset_spreadsheet&type=spreadsheet"
|
|
431
|
+
"&anchor=sheet_range&sheet_id=0&range=B2%3AB8",
|
|
432
|
+
excerpt="20,049 total vulnerabilities",
|
|
433
|
+
display_value="Vulnerability total",
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Typed helper path: still fine when the SDK has the source/anchor dataclasses.
|
|
406
437
|
citation_id = p.add_citation(
|
|
407
438
|
AssetReference(id="asset_spreadsheet"),
|
|
408
439
|
anchor=SheetRangeAnchor(sheet_id=0, range="B2:B8"),
|
|
@@ -444,7 +475,7 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
444
475
|
Format ops on cell-inner paragraphs (`paragraph.alignment`,
|
|
445
476
|
`paragraph.style`, every `paragraph_format` setter, and
|
|
446
477
|
`paragraph.add_hyperlink`) used to cascade-fail the entire HTTP
|
|
447
|
-
batch.
|
|
478
|
+
batch. The current docx-editor applier's
|
|
448
479
|
``SetParagraphAlignment``/``SetParagraphStyle``/``SetParagraphIndentation``/``SetParagraphSpacing``/``CreateHyperlink``
|
|
449
480
|
reject cell-inner block targets with ``BlockNotFoundError``, and the
|
|
450
481
|
applier's all-or-nothing batch model meant one cell-paragraph
|
|
@@ -458,7 +489,7 @@ instead of forwarding the broken command. The format op is dropped,
|
|
|
458
489
|
the surrounding batch survives, and the workaround pointer (
|
|
459
490
|
``cell.text = 'value'`` to materialize, then ``cell.paragraphs[0]``
|
|
460
491
|
for the addressable proxy) is in the warning text. Tracked at
|
|
461
|
-
``docx-studio/
|
|
492
|
+
``docx-studio/DOCX_STUDIO_LIMITATIONS.md`` § 13.
|
|
462
493
|
|
|
463
494
|
**0.11.5 follow-up: post-export OOXML rewrite.** When the parent
|
|
464
495
|
table was created via ``Document.add_table`` in this session
|
|
@@ -468,7 +499,7 @@ OOXML-shaped props (``alignment``, ``style``, ``left_twips``,
|
|
|
468
499
|
:class:`docx._postproc.PostExportOps` collector). ``Document.export_docx``
|
|
469
500
|
applies them via an OOXML rewrite of ``word/document.xml`` before
|
|
470
501
|
returning bytes — so the **exported ``.docx`` carries the formatting
|
|
471
|
-
the agent asked for** even though
|
|
502
|
+
the agent asked for** even though DOCX Studio never accepted the wire
|
|
472
503
|
op. Live-session state is unchanged (Olympus collaborators don't
|
|
473
504
|
see the formatting until export). Template-seeded tables where
|
|
474
505
|
``_doc_index`` is ``None`` still warn-and-skip (no stable OOXML
|
|
@@ -487,7 +518,7 @@ helper pattern —
|
|
|
487
518
|
|
|
488
519
|
— used to silently drop both the ``Hello world`` text AND the bold
|
|
489
520
|
format because ``Paragraph.add_run`` on a cell-inner paragraph
|
|
490
|
-
returned a stub Run with collapsed range, and
|
|
521
|
+
returned a stub Run with collapsed range, and the docx-editor applier
|
|
491
522
|
rejected the wire-level ``doc.insert`` against the cell-inner
|
|
492
523
|
paragraph's blockId with ``Block <id> not found``. The 0.13.0 fix
|
|
493
524
|
adds a ``_cell`` back-reference to every cell-inner Paragraph proxy
|
|
@@ -497,7 +528,7 @@ called on a cell-inner paragraph with non-empty text AND the
|
|
|
497
528
|
back-ref is set, the SDK ships ``doc.insert(target=cell,
|
|
498
529
|
placement="insideEnd", content=paragraph-fragment-with-text)``
|
|
499
530
|
instead — the SAME wire path ``_Cell.add_paragraph(text)`` already
|
|
500
|
-
uses.
|
|
531
|
+
uses. DOCX Studio collapses the new paragraph into the cell's single
|
|
501
532
|
template paragraph as an inline run; the exported DOCX expands each
|
|
502
533
|
non-empty inline run into its own ``<w:p>``. The returned Run is
|
|
503
534
|
real (non-collapsed range) and carries the new exported-paragraph
|
|
@@ -524,10 +555,10 @@ of dropping it silently at the wire layer. The post-export rewrite
|
|
|
524
555
|
walks every ``<w:r>`` in the targeted cell paragraph and injects
|
|
525
556
|
``<w:rPr>`` carrying the props — so ``cell.text = "Total"; cell.
|
|
526
557
|
paragraphs[0].runs[0].bold = True`` produces a bold ``Total`` in
|
|
527
|
-
the exported ``.docx`` even though
|
|
558
|
+
the exported ``.docx`` even though DOCX Studio never committed the
|
|
528
559
|
format wire op. Apply-to-all-runs semantics: the rewrite targets
|
|
529
560
|
every ``<w:r>`` in the cell paragraph, because run-level addressing
|
|
530
|
-
inside a cell isn't recoverable after
|
|
561
|
+
inside a cell isn't recoverable after DOCX Studio collapses cell-
|
|
531
562
|
inner inserts. Multi-run cell paragraphs with partial-run
|
|
532
563
|
formatting are a documented limitation — agents should use one
|
|
533
564
|
run per format intent.
|
|
@@ -550,7 +581,7 @@ rels entry so the rels file doesn't grow unboundedly. Behavior
|
|
|
550
581
|
pinned by ``tests/test_postproc_cell_run_format_rewrite.py``.
|
|
551
582
|
|
|
552
583
|
Live Olympus rendering still won't show cell-inner formatting or
|
|
553
|
-
hyperlinks until
|
|
584
|
+
hyperlinks until DOCX Studio lands the corresponding wire ops —
|
|
554
585
|
``Document.export_docx`` is the source of truth for the
|
|
555
586
|
deliverable until then.
|
|
556
587
|
|
|
@@ -565,7 +596,7 @@ deliverable until then.
|
|
|
565
596
|
workaround pointer and avoids re-issuing the slow query.
|
|
566
597
|
- **`Table._fresh_node_info` rotation tracking.** Each ``Table``
|
|
567
598
|
created via ``Document.add_table`` records its document-order
|
|
568
|
-
position as ``_doc_index``. When
|
|
599
|
+
position as ``_doc_index``. When DOCX Studio rotates the table's
|
|
569
600
|
nodeId between saves, the fallback resolves the rotated address
|
|
570
601
|
by position instead of always picking the last ``doc.find`` item.
|
|
571
602
|
Pre-0.11.4 the "take the last" heuristic silently mapped N
|
|
@@ -584,18 +615,18 @@ deliverable until then.
|
|
|
584
615
|
every other field kind) now emits ``at.segments`` with
|
|
585
616
|
``[{blockId, start, end}]`` instead of the ``{kind: "selection",
|
|
586
617
|
start, end}`` cursor envelope used by other create-ops.
|
|
587
|
-
|
|
588
|
-
``
|
|
618
|
+
DOCX Studio's ``doc.fields.insert`` rejects the cursor form with
|
|
619
|
+
``DocxStudioCommandError: fields insert:at.segments is required``;
|
|
589
620
|
pre-0.11.4 the call took down the whole batch on every flush.
|
|
590
621
|
|
|
591
622
|
### 0.11.5 — `REF` field round-trip preservation (post-export rewrite)
|
|
592
623
|
|
|
593
|
-
|
|
624
|
+
The DOCX editor import/export path can strip ``REF`` field codes
|
|
594
625
|
(``<w:fldChar>`` / ``<w:instrText REF …>`` / result-runs / end
|
|
595
626
|
``<w:fldChar>``) on import. On the Paul Weiss Purchase Agreement
|
|
596
627
|
this loses all 301 cross-references — readers see chains of empty
|
|
597
628
|
commas instead of "Section 3.02(b)" cross-refs. Tracked at
|
|
598
|
-
``docx-studio/
|
|
629
|
+
``docx-studio/DOCX_STUDIO_LIMITATIONS.md`` § 18.
|
|
599
630
|
|
|
600
631
|
As of 0.11.5, ``Document.create(docx=template.docx)`` scans the
|
|
601
632
|
local template bytes with a stdlib zipfile + xml.etree parser and
|
|
@@ -614,7 +645,7 @@ same Python process that called ``Document.create(docx=...)`` also
|
|
|
614
645
|
calls ``export_docx``. Cross-process flows (agent A creates, agent
|
|
615
646
|
B exports) need agora-side persistence (separate follow-up). (2)
|
|
616
647
|
Paragraph-wholesale replacement preserves the source paragraph but
|
|
617
|
-
overwrites any
|
|
648
|
+
overwrites any DOCX Studio in-paragraph edits — for round-trip
|
|
618
649
|
preservation (the primary use case) this is exactly right. (3) Only
|
|
619
650
|
top-level body paragraphs are scanned; cell-inner REFs aren't
|
|
620
651
|
captured (rare for legal cross-references).
|
|
@@ -643,9 +674,9 @@ routing, `add_picture` native size + aspect ratio, `WD_BUILTIN_STYLE`
|
|
|
643
674
|
and `CoreProperties` validation. These are not deviations — they close
|
|
644
675
|
gaps. The items below are the **residual intentional deviations** that
|
|
645
676
|
remain because matching upstream would break the asset-backed/HTTP
|
|
646
|
-
architecture or a
|
|
677
|
+
architecture or a DOCX Studio constraint:
|
|
647
678
|
|
|
648
|
-
- **`WD_*` enum `.value` is the
|
|
679
|
+
- **`WD_*` enum `.value` is the DOCX Studio wire string, not the MS Word
|
|
649
680
|
integer constant.** `WD_ALIGN_PARAGRAPH.CENTER.value == "center"`
|
|
650
681
|
(upstream: `1`); `int(member)` / `member == 1` / `WD_*(1)` therefore
|
|
651
682
|
differ. The string value is load-bearing — every command serializes
|
|
@@ -661,7 +692,7 @@ architecture or a SuperDoc constraint:
|
|
|
661
692
|
stripped before the (otherwise byte-identical) upstream slice parse.
|
|
662
693
|
A strict superset — every value upstream accepts parses identically.
|
|
663
694
|
|
|
664
|
-
- **`_Cell.vertical_alignment` setter accepts the four
|
|
695
|
+
- **`_Cell.vertical_alignment` setter accepts the four DOCX Studio wire
|
|
665
696
|
tokens** (`"top"`/`"center"`/`"bottom"`/`"both"`) in addition to
|
|
666
697
|
`WD_ALIGN_VERTICAL` members. Upstream rejects all plain strings; this
|
|
667
698
|
is an ergonomic superset (typos like `"middle"` still raise
|
|
@@ -685,19 +716,19 @@ architecture or a SuperDoc constraint:
|
|
|
685
716
|
|
|
686
717
|
- **`Document.add_table(rows, cols)` requires `rows >= 1` and
|
|
687
718
|
`cols >= 1`.** Upstream allows a 0-row/0-col grid you later populate,
|
|
688
|
-
but
|
|
719
|
+
but DOCX Studio's ProseMirror table node can't represent one; the SDK
|
|
689
720
|
raises eagerly rather than failing opaquely on the wire.
|
|
690
721
|
|
|
691
|
-
- **`Comment.comment_id` returns `str`, not `int`.**
|
|
722
|
+
- **`Comment.comment_id` returns `str`, not `int`.** DOCX Studio uses
|
|
692
723
|
non-numeric entity ids (`"c-42"`), so the upstream `int` contract
|
|
693
|
-
can't be honored. Tracked in `
|
|
724
|
+
can't be honored. Tracked in `DOCX_STUDIO_LIMITATIONS.md`.
|
|
694
725
|
|
|
695
726
|
- **`Section` dimension setters and `ParagraphFormat.line_spacing_rule
|
|
696
727
|
= None` warn-and-preserve on a clear** rather than raising (upstream
|
|
697
|
-
accepts `None` to clear, but
|
|
728
|
+
accepts `None` to clear, but DOCX Studio's merging mutation ops have no
|
|
698
729
|
single-attribute clear). They emit a `Pending…ClearWarning` and leave
|
|
699
730
|
the value intact instead of destructively clearing the whole block.
|
|
700
|
-
Tracked in `
|
|
731
|
+
Tracked in `DOCX_STUDIO_LIMITATIONS.md`.
|
|
701
732
|
|
|
702
733
|
### If you need a deviation
|
|
703
734
|
|
|
@@ -723,13 +754,13 @@ This is a **thin HTTP client** that mimics the sync python-docx API.
|
|
|
723
754
|
(a `SessionError`) carrying `http_status` and an optional
|
|
724
755
|
`retry_after_seconds` parsed from the server's `Retry-After` header.
|
|
725
756
|
Agent code can catch this typed error to back off at the agent level
|
|
726
|
-
vs. treating it as a script bug. The
|
|
727
|
-
(embedded
|
|
728
|
-
0.5.0; agent pods no longer embed
|
|
757
|
+
vs. treating it as a script bug. The former `transport="direct"`
|
|
758
|
+
(embedded DOCX Studio CLI + y-websocket from Python) was removed in
|
|
759
|
+
0.5.0; agent pods no longer embed DOCX Studio.
|
|
729
760
|
- **Transparent batching (0.7.0+):** Create* commands
|
|
730
761
|
(`CreateParagraph`, `CreateHeading`, `CreateTable`, `CreateImage`)
|
|
731
762
|
ALWAYS pre-mint a client-side UUID (`client_node_id`) and defer
|
|
732
|
-
through the buffer. The applier resolves UUIDs to real
|
|
763
|
+
through the buffer. The applier resolves UUIDs to real DOCX Studio
|
|
733
764
|
ids via per-batch `clientIdMap` on flush, and the buffer rewrites
|
|
734
765
|
each proxy's `_node_id` in-place. Net result: 30 `add_paragraph`
|
|
735
766
|
calls = 1 HTTP request, with no explicit `batch()` context manager
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.2
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -21,9 +21,6 @@ Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
|
21
21
|
Requires-Dist: python-docx>=1.1; extra == 'dev'
|
|
22
22
|
Requires-Dist: responses>=0.24; extra == 'dev'
|
|
23
23
|
Requires-Dist: ruff>=0.3; extra == 'dev'
|
|
24
|
-
Provides-Extra: fidelity
|
|
25
|
-
Requires-Dist: httpx>=0.27; extra == 'fidelity'
|
|
26
|
-
Requires-Dist: superdoc-sdk>=1.8.0; extra == 'fidelity'
|
|
27
24
|
Description-Content-Type: text/markdown
|
|
28
25
|
|
|
29
26
|
# athena-python-docx
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""athena-python-docx — drop-in replacement for python-docx.
|
|
2
2
|
|
|
3
|
-
Calls translate into
|
|
3
|
+
Calls translate into DOCX Studio SDK operations against a Keryx Y.Doc.
|
|
4
4
|
See CLAUDE.md for the API parity contract.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
__version__ = "0.21.
|
|
9
|
+
__version__ = "0.21.2"
|
|
10
10
|
|
|
11
11
|
from docx.api import Document
|
|
12
12
|
from docx._buffer import flush_all
|
|
@@ -8,7 +8,7 @@ ships as one HTTP request instead of N.
|
|
|
8
8
|
Create* commands are deferred because the SDK pre-mints a client-side
|
|
9
9
|
UUID for every new node (see ``Document._mint_client_node_id``). The
|
|
10
10
|
proxy returned to the caller is stamped with that UUID; the applier
|
|
11
|
-
resolves UUIDs to real
|
|
11
|
+
resolves UUIDs to real DOCX Studio ids via ``clientIdMap`` and echoes the
|
|
12
12
|
mapping back, at which point the buffer rewrites each proxy's
|
|
13
13
|
``_node_id``. This makes batching invisible at the call site — user
|
|
14
14
|
code looks like python-docx, runs at python-docx-batched speed.
|
|
@@ -49,7 +49,7 @@ def _apply_proxy_id_rewrites(
|
|
|
49
49
|
proxy_id_refs: "dict[str, list[tuple[object, str]]]",
|
|
50
50
|
) -> None:
|
|
51
51
|
"""Walk ``results`` and rewrite registered proxy ids from client UUIDs
|
|
52
|
-
to the real
|
|
52
|
+
to the real DOCX Studio ids the applier echoed back.
|
|
53
53
|
|
|
54
54
|
Shared by the success path in :meth:`CommandBuffer.flush` /
|
|
55
55
|
:meth:`_eager_flush_with` AND by the **partial-failure recovery
|
|
@@ -287,7 +287,7 @@ class CommandBuffer:
|
|
|
287
287
|
|
|
288
288
|
Create* commands defer because the SDK pre-mints a client-side UUID
|
|
289
289
|
(``client_node_id`` / ``client_entity_id``); the applier translates
|
|
290
|
-
the UUID to a real
|
|
290
|
+
the UUID to a real DOCX Studio id in a per-batch ``clientIdMap`` and
|
|
291
291
|
echoes the mapping back so the SDK can rewrite each proxy's
|
|
292
292
|
``_node_id`` on flush.
|
|
293
293
|
"""
|
|
@@ -385,7 +385,7 @@ class CommandBuffer:
|
|
|
385
385
|
def set_user(self, name: str | None, email: str | None = None) -> None:
|
|
386
386
|
"""Set the batch-level user identity.
|
|
387
387
|
|
|
388
|
-
Sent on every commands request envelope.
|
|
388
|
+
Sent on every commands request envelope. DOCX Studio honors the
|
|
389
389
|
identity at session-open time only — subsequent batches against
|
|
390
390
|
a pooled session ignore the value, but the payload is still
|
|
391
391
|
included so a fresh session picks it up.
|
|
@@ -415,7 +415,7 @@ class CommandBuffer:
|
|
|
415
415
|
``client_entity_id`` — appends to the queue, resets the idle
|
|
416
416
|
timer, and returns ``None``. Caller MUST NOT rely on the return
|
|
417
417
|
value of a buffered mutation. For deferred Creates, the
|
|
418
|
-
applier resolves the client UUID to a real
|
|
418
|
+
applier resolves the client UUID to a real DOCX Studio id via
|
|
419
419
|
``clientIdMap`` on flush and the buffer rewrites each registered
|
|
420
420
|
proxy's ``_node_id`` in-place.
|
|
421
421
|
"""
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Helpers for SDK-native Athena citations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
from typing import Any
|
|
7
|
+
from urllib.parse import parse_qs, urlparse
|
|
8
|
+
|
|
9
|
+
from docx._references import AssetReference
|
|
10
|
+
from docx.commands import AddCitation
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
_ATHENA_SPACES_HOST_SUFFIXES: tuple[str, ...] = (
|
|
14
|
+
"athenaintel.com",
|
|
15
|
+
"athenaintelligence.ai",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def new_citation_id() -> str:
|
|
20
|
+
return f"citation_{uuid.uuid4().hex[:12]}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_athena_spaces_host(hostname: str | None) -> bool:
|
|
24
|
+
host = (hostname or "").lower()
|
|
25
|
+
return any(
|
|
26
|
+
host == suffix or host.endswith(f".{suffix}")
|
|
27
|
+
for suffix in _ATHENA_SPACES_HOST_SUFFIXES
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def source_ref_to_dict(source: AssetReference) -> dict[str, Any]:
|
|
32
|
+
if not isinstance(source, AssetReference):
|
|
33
|
+
raise TypeError(f"source must be an AssetReference; got {type(source).__name__}")
|
|
34
|
+
return source.to_dict()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def normalize_citation_string(citation_string: str) -> str:
|
|
38
|
+
value = citation_string.strip()
|
|
39
|
+
if not value:
|
|
40
|
+
raise ValueError("citation_string must not be empty")
|
|
41
|
+
|
|
42
|
+
parsed = urlparse(value)
|
|
43
|
+
if parsed.scheme in ("http", "https") and parsed.netloc:
|
|
44
|
+
if parsed.path.rstrip("/") == "/dashboard/spaces":
|
|
45
|
+
if not _is_athena_spaces_host(parsed.hostname):
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"absolute Athena Spaces citation URLs must use an Athena host"
|
|
48
|
+
)
|
|
49
|
+
asset_ids = parse_qs(parsed.query).get("asset_ids")
|
|
50
|
+
if not asset_ids or not asset_ids[0]:
|
|
51
|
+
raise ValueError("Athena Spaces citation URLs must include asset_ids")
|
|
52
|
+
return value
|
|
53
|
+
|
|
54
|
+
if not parsed.scheme and value.startswith("/"):
|
|
55
|
+
relative = urlparse(value)
|
|
56
|
+
if relative.netloc:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
"protocol-relative Athena Spaces citation URLs are not allowed; "
|
|
59
|
+
"use an absolute Athena host"
|
|
60
|
+
)
|
|
61
|
+
if relative.path.rstrip("/") == "/dashboard/spaces":
|
|
62
|
+
asset_ids = parse_qs(relative.query).get("asset_ids")
|
|
63
|
+
if asset_ids and asset_ids[0]:
|
|
64
|
+
return value
|
|
65
|
+
raise ValueError("Athena Spaces citation URLs must include asset_ids")
|
|
66
|
+
|
|
67
|
+
raise ValueError(
|
|
68
|
+
"citation_string must be a serialized citation URL, such as "
|
|
69
|
+
"'/dashboard/spaces/?asset_ids=...' or an 'https://...' URL"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def anchor_to_dict(anchor: object | None) -> dict[str, Any] | None:
|
|
74
|
+
if anchor is None:
|
|
75
|
+
return None
|
|
76
|
+
if not hasattr(anchor, "to_dict"):
|
|
77
|
+
raise TypeError(
|
|
78
|
+
"anchor must be an Anchor dataclass (SheetRangeAnchor, "
|
|
79
|
+
f"PmNodeAnchor, etc.) — got {type(anchor).__name__}"
|
|
80
|
+
)
|
|
81
|
+
value = anchor.to_dict()
|
|
82
|
+
if not isinstance(value, dict) or not value.get("type"):
|
|
83
|
+
raise TypeError("anchor.to_dict() must return a dict with a 'type' field")
|
|
84
|
+
return value
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def destination_anchor_to_dict(destination_anchor: object) -> dict[str, Any]:
|
|
88
|
+
if hasattr(destination_anchor, "to_dict"):
|
|
89
|
+
destination_anchor = destination_anchor.to_dict()
|
|
90
|
+
if not isinstance(destination_anchor, dict):
|
|
91
|
+
raise TypeError(
|
|
92
|
+
"destination_anchor must be a PmNodeAnchor, PmNodeRangeAnchor, or wire dict"
|
|
93
|
+
)
|
|
94
|
+
anchor_type = destination_anchor.get("type")
|
|
95
|
+
if anchor_type == "pm_node" and destination_anchor.get("nodeId"):
|
|
96
|
+
return dict(destination_anchor)
|
|
97
|
+
if (
|
|
98
|
+
anchor_type == "pm_node_range"
|
|
99
|
+
and destination_anchor.get("startNodeId")
|
|
100
|
+
and destination_anchor.get("endNodeId")
|
|
101
|
+
):
|
|
102
|
+
return dict(destination_anchor)
|
|
103
|
+
raise ValueError(
|
|
104
|
+
"destination_anchor must be {'type':'pm_node','nodeId':...} or "
|
|
105
|
+
"{'type':'pm_node_range','startNodeId':...,'endNodeId':...}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def build_add_citation_command(
|
|
110
|
+
*,
|
|
111
|
+
destination_anchor: object,
|
|
112
|
+
source: AssetReference | str | None,
|
|
113
|
+
anchor: object | None,
|
|
114
|
+
citation_string: str | None,
|
|
115
|
+
excerpt: str | None,
|
|
116
|
+
display_value: str | None,
|
|
117
|
+
) -> tuple[str, AddCitation]:
|
|
118
|
+
source_ref: dict[str, Any] | None
|
|
119
|
+
if isinstance(source, str):
|
|
120
|
+
if (
|
|
121
|
+
citation_string is not None
|
|
122
|
+
and normalize_citation_string(citation_string)
|
|
123
|
+
!= normalize_citation_string(source)
|
|
124
|
+
):
|
|
125
|
+
raise ValueError("Pass citation_string either positionally or by keyword, not both")
|
|
126
|
+
citation_string = source
|
|
127
|
+
source_ref = None
|
|
128
|
+
elif source is None:
|
|
129
|
+
source_ref = None
|
|
130
|
+
else:
|
|
131
|
+
if citation_string is not None:
|
|
132
|
+
raise ValueError("Pass either an AssetReference source or citation_string, not both")
|
|
133
|
+
source_ref = source_ref_to_dict(source)
|
|
134
|
+
|
|
135
|
+
normalized_citation_string = (
|
|
136
|
+
normalize_citation_string(citation_string)
|
|
137
|
+
if citation_string is not None
|
|
138
|
+
else None
|
|
139
|
+
)
|
|
140
|
+
if source_ref is None and normalized_citation_string is None:
|
|
141
|
+
raise ValueError("source or citation_string is required")
|
|
142
|
+
if source_ref is None and anchor is not None:
|
|
143
|
+
raise ValueError("anchor requires an AssetReference source; encode the anchor in citation_string instead")
|
|
144
|
+
|
|
145
|
+
citation_id = new_citation_id()
|
|
146
|
+
return citation_id, AddCitation(
|
|
147
|
+
destination_anchor=destination_anchor_to_dict(destination_anchor),
|
|
148
|
+
source_ref=source_ref,
|
|
149
|
+
source_anchor=anchor_to_dict(anchor),
|
|
150
|
+
citation_string=normalized_citation_string,
|
|
151
|
+
citation_id=citation_id,
|
|
152
|
+
excerpt=excerpt,
|
|
153
|
+
display_value=display_value,
|
|
154
|
+
)
|