athena-python-docx 0.29.0__tar.gz → 0.30.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.29.0 → athena_python_docx-0.30.0}/AGENTS.md +44 -11
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/PKG-INFO +1 -1
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_http_doc.py +12 -4
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_postproc.py +25 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_tracked.py +11 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/commands.py +20 -2
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/comments.py +4 -2
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/document.py +2 -1
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/paragraph.py +78 -3
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/pyproject.toml +1 -1
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/baseline.json +2 -6
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extensions_registry.py +1 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_http_transport.py +1 -1
- athena_python_docx-0.30.0/tests/test_paragraph_delete.py +186 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_ref_restore.py +48 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_tracked_revisions_offsets.py +28 -15
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_wire_contract.py +1 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/uv.lock +1 -1
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/.gitignore +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/CLAUDE.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/README.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_capabilities.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_citations.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_http.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_references.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_run_order.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/api.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/blkcntnr.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/charts.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/client.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/drawing/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/base.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/dml.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/errors.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/fields.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/exceptions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/image/image.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/math.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/section.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/session.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/settings.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/shape.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/shared.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/_table.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/latent.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/table.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/run.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/toc.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/docx/typing.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/field_reads.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/note_reference_reads.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/ruby_reads.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/fixtures/symbol_reads.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/reader.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/runner.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/sdk_driver.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/stock_driver.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/live/test_live_runner.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_add_section.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extension_creates_session_open.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_batch_chunking.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_borders_spec.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_fastpath_runs.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_inner_run_guard.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_merge.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_paragraphs_listed.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_citations.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_color_format_theme.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_comment_paragraphs.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_content_control_value.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_core_properties.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_drawing_image.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_empty_hyperlinks.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_enum_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_export_docx_clean.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_refresh.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_field_runs.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_page_break.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_alt_text.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_size.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shape_type.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_inline_shapes_floating.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_missing_modules.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_page_break.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_pdf_export_and_page_renders.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_read_run_ranges.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_repeated_node_read.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_restart_numbering.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_round_trip_smoke_script.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_add_picture_anchor.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_edges.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_formatting_wire.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_identity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_mark_inheritance.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_table_style_objects.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_text_python_docx.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_sdk_reads_served.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_section_read_lengths.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_formatting_writes.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_metadata_writes.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_names.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_read_reuse.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_text_control_characters.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_uv_lock_version.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -204,14 +204,21 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
204
204
|
are sent with `changeMode: "tracked"`, and docx-studio records their text
|
|
205
205
|
edits as Word revisions (`w:ins` / `w:del`): run and paragraph text,
|
|
206
206
|
`find_replace` in the body, new paragraphs and headings (an inserted
|
|
207
|
-
paragraph mark),
|
|
207
|
+
paragraph mark), whole paragraphs deleted (`paragraph.delete()`, 0.30.0+:
|
|
208
|
+
its content, fields included, and its paragraph mark), tabs and line breaks,
|
|
209
|
+
run formatting (`w:rPrChange`) and
|
|
208
210
|
`paragraph_format` properties (`w:pPrChange`). The replaced text stays, deleted,
|
|
209
211
|
and the new text follows it, so the SDK keeps its paragraph lengths and
|
|
210
212
|
run ranges that way (`docx/_tracked.py`): a tracked `run.text = value`
|
|
211
213
|
leaves the run over `value`, after its deleted text, and the paragraph
|
|
212
|
-
grows by `len(value)`.
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
grows by `len(value)`. `find_replace` and (0.30.0+) `paragraph.text = value`
|
|
215
|
+
mark only the words that change, the words the old and new text share at
|
|
216
|
+
their start and end left as they are, so after a tracked `paragraph.text`
|
|
217
|
+
the SDK reads the paragraph's length back. Every batch says so to docx-studio
|
|
218
|
+
(`client.capabilities: ["trackedAuthoring", "trackedMinimalParagraphText"]`);
|
|
219
|
+
a docx-studio refuses a tracked edit from an SDK that does not declare
|
|
220
|
+
`trackedAuthoring`, and replaces a paragraph's whole text for one that
|
|
221
|
+
does not declare `trackedMinimalParagraphText`. A batch holding an edit it cannot
|
|
215
222
|
record yet (paragraph styles, tables, pictures, lists, sections, notes,
|
|
216
223
|
page breaks, header/footer/comment text) is refused (HTTP 422,
|
|
217
224
|
`TrackedChangesUnsupported`) and applies nothing; reads, exports,
|
|
@@ -233,9 +240,11 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
233
240
|
|
|
234
241
|
- **`Document.user_name: str | None` / `Document.user_email: str |
|
|
235
242
|
None`** — the name sent with each batch, which DOCX Studio uses as the
|
|
236
|
-
author of a comment that names none
|
|
237
|
-
|
|
238
|
-
|
|
243
|
+
author of a comment that names none (unset, such a comment is by the
|
|
244
|
+
signed-in user, as "Jane Doe (Athena)"). It is not a tracked change's
|
|
245
|
+
author: DOCX Studio stamps those with the signed-in user agora's access
|
|
246
|
+
check names, as an agent writes for them ("Jane Doe (Athena)"), so a
|
|
247
|
+
script cannot choose who a redline's changes are by.
|
|
239
248
|
Separate from `Document.core_properties.last_modified_by`, the
|
|
240
249
|
`docProps/core.xml` metadata the SDK reads and writes as python-docx
|
|
241
250
|
does.
|
|
@@ -451,6 +460,26 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
451
460
|
numbering reads. python-docx issue #471 (13 👍) demands access to
|
|
452
461
|
list metadata. Routes through `NumberingGet`.
|
|
453
462
|
|
|
463
|
+
- **`Paragraph.delete()`** (0.30.0+) — delete the paragraph, its
|
|
464
|
+
paragraph mark included. python-docx has no paragraph delete (issue #33);
|
|
465
|
+
code written for it removes the element
|
|
466
|
+
(`p._element.getparent().remove(p._element)`), which this SDK cannot reach.
|
|
467
|
+
Routes through `DeleteParagraph`, sent in a request of its own after the
|
|
468
|
+
buffered edits (response-bearing, so a refusal raises at the call). With
|
|
469
|
+
tracking off docx-studio removes the paragraph, with the page and column
|
|
470
|
+
breaks the import keeps beside it; with `track_revisions` on it records
|
|
471
|
+
Word's tracked deletion of a whole paragraph: its content in `w:del`
|
|
472
|
+
(cross-reference and other fields with their codes and results, links,
|
|
473
|
+
note references) and its paragraph mark deleted, one revision. Accept All
|
|
474
|
+
removes it and the numbered paragraphs after it number on; Reject All
|
|
475
|
+
restores it. `paragraph.text = ""` leaves an empty, still numbered,
|
|
476
|
+
paragraph instead. docx-studio refuses (`DocxError`, nothing applied) the
|
|
477
|
+
document's last paragraph, one that ends a section, the only paragraph of
|
|
478
|
+
a table cell or content control, one holding part of a field that spans
|
|
479
|
+
paragraphs, one in a header, footer, comment or text box, and, tracked,
|
|
480
|
+
one in a table cell or holding a page break, a content control, a shape or
|
|
481
|
+
an equation (`DOCX_STUDIO_LIMITATIONS.md` § 32).
|
|
482
|
+
|
|
454
483
|
- **`Paragraph.restart_numbering(start=1)`** (0.26.0+) — restart the
|
|
455
484
|
paragraph's numbered list at `start`, as Word's "Restart at 1" does
|
|
456
485
|
("Set Numbering Value" for another start). All `"List Number"`
|
|
@@ -648,8 +677,11 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
648
677
|
leaves out the author, last-modified-by, revision, company, manager,
|
|
649
678
|
template, editing-time and hyperlink-base properties, rsids, document
|
|
650
679
|
variables, custom properties, Custom XML (a content control bound to it
|
|
651
|
-
keeps its content, not its binding), the attached template
|
|
652
|
-
thumbnail; ``clear_title=True`` drops the title too.
|
|
680
|
+
keeps its content, not its binding), the attached template, the attached
|
|
681
|
+
XML schema and the thumbnail; ``clear_title=True`` drops the title too.
|
|
682
|
+
Bookmarks, the creation date and the sensitivity label stay (the route's
|
|
683
|
+
``removeSensitivityLabel=1`` drops the label; the SDK does not send it).
|
|
684
|
+
The live document is
|
|
653
685
|
not changed. The SDK refuses (``DocxUnsupportedCommandError``) an answer
|
|
654
686
|
without ``X-Docx-Clean-Copy: 1``, the plain export an older docx-studio
|
|
655
687
|
sends, and raises ``DocxError`` with docx-studio's reason when a header,
|
|
@@ -990,8 +1022,9 @@ architecture or a DOCX Studio constraint:
|
|
|
990
1022
|
`""`.** `Document.add_comment` / `Comments.add_comment` send `author`
|
|
991
1023
|
and `initials` and docx-studio stores them as `w:author` /
|
|
992
1024
|
`w:initials`, as python-docx does; with none (python-docx's default
|
|
993
|
-
`""`) the author is `Document.user_name`, else
|
|
994
|
-
|
|
1025
|
+
`""`) the author is `Document.user_name`, else the signed-in user agora's
|
|
1026
|
+
access check names as an agent writes for them, "Jane Doe (Athena)" (the
|
|
1027
|
+
author of the batch's tracked changes), else `"Athena"`, and no initials are stored (`initials` then reads `None`). The SDK raises
|
|
995
1028
|
`ValueError` for what lxml refuses in an attribute, as python-docx
|
|
996
1029
|
does, and also past docx-studio's caps (255 UTF-16 code units for an
|
|
997
1030
|
author, 32 for initials); docx-studio turns tabs, line breaks and other
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.0
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -4,7 +4,8 @@ Wire format (matches ``apps/api/src/commands/types.ts``):
|
|
|
4
4
|
|
|
5
5
|
POST /docs/:id/commands
|
|
6
6
|
{
|
|
7
|
-
"client": {"type": "python-sdk", "version": "<x.y.z>",
|
|
7
|
+
"client": {"type": "python-sdk", "version": "<x.y.z>",
|
|
8
|
+
"capabilities": ["trackedAuthoring", "trackedMinimalParagraphText"]},
|
|
8
9
|
"commands": [
|
|
9
10
|
{"type": "CreateParagraph", "text": "Hi", "at": {"kind": "documentEnd"}},
|
|
10
11
|
...
|
|
@@ -42,7 +43,7 @@ from urllib3.util.retry import Retry
|
|
|
42
43
|
|
|
43
44
|
from docx._batching import call_abandoned, note_progress
|
|
44
45
|
from docx._buffer import CommandBuffer
|
|
45
|
-
from docx._tracked import TRACKED_AUTHORING_CAPABILITY
|
|
46
|
+
from docx._tracked import TRACKED_AUTHORING_CAPABILITY, TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY
|
|
46
47
|
from docx._timeouts import (
|
|
47
48
|
DEFAULT_OP_TIMEOUT_SECONDS,
|
|
48
49
|
LONG_RUNNING_COMMAND_TIMEOUT_SECONDS,
|
|
@@ -89,6 +90,7 @@ from docx.commands import (
|
|
|
89
90
|
CreateTOC,
|
|
90
91
|
CreateWatermark,
|
|
91
92
|
DeleteBookmark,
|
|
93
|
+
DeleteParagraph,
|
|
92
94
|
DeleteWatermark,
|
|
93
95
|
EndnotesDelete,
|
|
94
96
|
EndnotesGet,
|
|
@@ -1194,8 +1196,13 @@ class HttpClient:
|
|
|
1194
1196
|
"client": {
|
|
1195
1197
|
"type": "python-sdk",
|
|
1196
1198
|
"version": _sdk_version(),
|
|
1197
|
-
# Keeps its offsets as a tracked edit moves them
|
|
1198
|
-
|
|
1199
|
+
# Keeps its offsets as a tracked edit moves them, and reads a
|
|
1200
|
+
# paragraph's length back after a tracked ``paragraph.text``
|
|
1201
|
+
# (``docx._tracked``).
|
|
1202
|
+
"capabilities": [
|
|
1203
|
+
TRACKED_AUTHORING_CAPABILITY,
|
|
1204
|
+
TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY,
|
|
1205
|
+
],
|
|
1199
1206
|
},
|
|
1200
1207
|
"commands": [
|
|
1201
1208
|
_with_real_ids(c.to_dict(), ids) if ids else c.to_dict() for c in commands
|
|
@@ -1475,6 +1482,7 @@ _OP_TO_COMMAND: dict[str, type[Command]] = {
|
|
|
1475
1482
|
"sections.set_columns": SetSectionColumns,
|
|
1476
1483
|
"find_replace": FindReplace,
|
|
1477
1484
|
"clear_body": ClearBody,
|
|
1485
|
+
"delete_paragraph": DeleteParagraph,
|
|
1478
1486
|
"find_text": FindText,
|
|
1479
1487
|
"iter_runs": IterRuns,
|
|
1480
1488
|
"export_pdf": ExportPDF,
|
|
@@ -520,6 +520,15 @@ class PostExportOps:
|
|
|
520
520
|
or bool(self._row_cant_split_ops)
|
|
521
521
|
)
|
|
522
522
|
|
|
523
|
+
def forget_captured_refs(self) -> None:
|
|
524
|
+
"""Drop the captured REF paragraphs (``Paragraph.delete``).
|
|
525
|
+
|
|
526
|
+
They are addressed by their index among the body's paragraphs, which
|
|
527
|
+
a deleted paragraph shifts, so a capture could restore over the
|
|
528
|
+
paragraph after the one it was taken from.
|
|
529
|
+
"""
|
|
530
|
+
self._captured_refs.clear()
|
|
531
|
+
|
|
523
532
|
def discard_body_ops(self) -> None:
|
|
524
533
|
"""Drop every rewrite that addresses body content by position.
|
|
525
534
|
|
|
@@ -1402,6 +1411,17 @@ def _count_ref_fields(p: ET.Element) -> int:
|
|
|
1402
1411
|
return count
|
|
1403
1412
|
|
|
1404
1413
|
|
|
1414
|
+
_REVISION_TAGS = frozenset(
|
|
1415
|
+
f"{W_NS}{name}" for name in ("ins", "del", "moveFrom", "moveTo", "delInstrText")
|
|
1416
|
+
)
|
|
1417
|
+
|
|
1418
|
+
|
|
1419
|
+
def _holds_revisions(p: ET.Element) -> bool:
|
|
1420
|
+
"""True when the paragraph holds tracked-change markup: an insertion,
|
|
1421
|
+
a deletion or a move, of its runs or of its paragraph mark."""
|
|
1422
|
+
return any(el.tag in _REVISION_TAGS for el in p.iter())
|
|
1423
|
+
|
|
1424
|
+
|
|
1405
1425
|
def _iter_captured_ref_paragraphs(
|
|
1406
1426
|
body: ET.Element,
|
|
1407
1427
|
) -> "Iterable[CapturedRefParagraph]":
|
|
@@ -1503,6 +1523,11 @@ def _restore_stripped_refs(
|
|
|
1503
1523
|
if _count_ref_fields(exported) >= entry.ref_count:
|
|
1504
1524
|
# DOCX Studio kept the REFs; nothing to do.
|
|
1505
1525
|
continue
|
|
1526
|
+
if _holds_revisions(exported):
|
|
1527
|
+
# A tracked change (a deleted paragraph's REF is a
|
|
1528
|
+
# ``w:delInstrText`` in a ``w:del``) is an edit, not a strip:
|
|
1529
|
+
# restoring the source would drop it from the export.
|
|
1530
|
+
continue
|
|
1506
1531
|
if _paragraph_fingerprint(exported) != entry.fingerprint:
|
|
1507
1532
|
# The paragraph diverged on round-trip — user edited it or
|
|
1508
1533
|
# DOCX Studio materially changed its text. Skip rather than
|
|
@@ -11,6 +11,13 @@ text in place.
|
|
|
11
11
|
The SDK declares that it keeps its offsets this way
|
|
12
12
|
(:data:`TRACKED_AUTHORING_CAPABILITY` in ``client.capabilities``); a
|
|
13
13
|
docx-studio records a python-sdk's tracked edits only from an SDK that does.
|
|
14
|
+
|
|
15
|
+
A tracked ``paragraph.text = value`` is the exception: docx-studio marks only
|
|
16
|
+
the words that change (the words the old and new text share at their start
|
|
17
|
+
and end stay as they are), so the paragraph's new length is known only to the
|
|
18
|
+
server. The SDK forgets the length and reads it back before the next edit
|
|
19
|
+
that needs it, and says so (:data:`TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY`);
|
|
20
|
+
a docx-studio replaces the whole text for an SDK that does not.
|
|
14
21
|
"""
|
|
15
22
|
|
|
16
23
|
from __future__ import annotations
|
|
@@ -20,6 +27,10 @@ from typing import Any
|
|
|
20
27
|
#: What the SDK tells docx-studio in ``client.capabilities`` on every batch.
|
|
21
28
|
TRACKED_AUTHORING_CAPABILITY = "trackedAuthoring"
|
|
22
29
|
|
|
30
|
+
#: Also sent: the SDK reads a paragraph's length back after a tracked
|
|
31
|
+
#: ``paragraph.text = value``, so docx-studio may mark only what changes.
|
|
32
|
+
TRACKED_MINIMAL_PARAGRAPH_TEXT_CAPABILITY = "trackedMinimalParagraphText"
|
|
33
|
+
|
|
23
34
|
|
|
24
35
|
def tracking(session: Any) -> bool:
|
|
25
36
|
"""True when ``session``'s writes go out with ``changeMode: "tracked"``
|
|
@@ -781,8 +781,8 @@ class CommentsCreate(Command):
|
|
|
781
781
|
target: dict[str, Any] | None = None
|
|
782
782
|
parent_id: str | None = None
|
|
783
783
|
# Word's ``w:author`` / ``w:initials`` (display text). Left unset, the
|
|
784
|
-
# comment's author is the batch's ``user.name``, else
|
|
785
|
-
# has no initials.
|
|
784
|
+
# comment's author is the batch's ``user.name``, else the user agora's
|
|
785
|
+
# access check names, else "Athena", and it has no initials.
|
|
786
786
|
author: str | None = None
|
|
787
787
|
initials: str | None = None
|
|
788
788
|
# Optional client-assigned entity id for transparent-batched
|
|
@@ -1770,6 +1770,19 @@ class ClearBody(Command):
|
|
|
1770
1770
|
"""
|
|
1771
1771
|
|
|
1772
1772
|
|
|
1773
|
+
@dataclass
|
|
1774
|
+
class DeleteParagraph(Command):
|
|
1775
|
+
"""Delete a whole body paragraph (:meth:`Paragraph.delete`).
|
|
1776
|
+
|
|
1777
|
+
Athena extension: python-docx has no paragraph delete. Direct, DOCX Studio
|
|
1778
|
+
removes the paragraph; with ``track_revisions`` it keeps it as Word's
|
|
1779
|
+
tracked deletion of its content and its paragraph mark, fields included,
|
|
1780
|
+
which Accept All removes and Reject All restores. Returns ``{changed}``.
|
|
1781
|
+
"""
|
|
1782
|
+
|
|
1783
|
+
block_id: str = ""
|
|
1784
|
+
|
|
1785
|
+
|
|
1773
1786
|
@dataclass
|
|
1774
1787
|
class FindText(Command):
|
|
1775
1788
|
"""Search document text and return bounded match context.
|
|
@@ -2003,6 +2016,9 @@ _RESPONSE_BEARING_TYPES: frozenset[str] = frozenset(
|
|
|
2003
2016
|
# ClearBody replaces the whole body; Document.clear awaits it so a
|
|
2004
2017
|
# rejected clear raises instead of leaving stale content behind.
|
|
2005
2018
|
"ClearBody",
|
|
2019
|
+
# DeleteParagraph returns {changed}; Paragraph.delete awaits it so a
|
|
2020
|
+
# refused delete raises at the call.
|
|
2021
|
+
"DeleteParagraph",
|
|
2006
2022
|
# TablesMergeCells returns the merged cell, which ``_Cell.merge``
|
|
2007
2023
|
# returns; an invalid span raises InvalidSpanError at the call, as in
|
|
2008
2024
|
# python-docx.
|
|
@@ -2104,6 +2120,7 @@ for _cls, _issue, _desc in [
|
|
|
2104
2120
|
(SetSectionColumns, "python-docx#167", "Section multi-column layout"),
|
|
2105
2121
|
(FindReplace, "python-docx#30", "Formatting-preserving find/replace"),
|
|
2106
2122
|
(ClearBody, None, "Document.clear — bulk body reset"),
|
|
2123
|
+
(DeleteParagraph, "python-docx#33", "Paragraph.delete — whole paragraph delete"),
|
|
2107
2124
|
(FindText, "python-docx#980", "Fast document text search"),
|
|
2108
2125
|
(IterRuns, "python-docx#980", "Run stream for run-isolation"),
|
|
2109
2126
|
(ExportPDF, "python-docx#113", "PDF export"),
|
|
@@ -2247,6 +2264,7 @@ __all__ = [
|
|
|
2247
2264
|
"SetSectionColumns",
|
|
2248
2265
|
"FindReplace",
|
|
2249
2266
|
"ClearBody",
|
|
2267
|
+
"DeleteParagraph",
|
|
2250
2268
|
"FindText",
|
|
2251
2269
|
"IterRuns",
|
|
2252
2270
|
"ExportPDF",
|
|
@@ -216,7 +216,8 @@ def _comment_display_fields(
|
|
|
216
216
|
so does docx-studio, as display text only: Keryx attributes the write
|
|
217
217
|
itself to the signed-in user (and agent). An empty author, python-docx's
|
|
218
218
|
default, is not sent, so the comment keeps the session's name
|
|
219
|
-
(``Document.user_name``, else "Athena"); empty
|
|
219
|
+
(``Document.user_name``, else the signed-in user, else "Athena"); empty
|
|
220
|
+
or ``None`` initials are
|
|
220
221
|
not sent either. docx-studio turns tabs, line breaks and other control
|
|
221
222
|
characters into spaces.
|
|
222
223
|
"""
|
|
@@ -492,7 +493,8 @@ class Comments:
|
|
|
492
493
|
``w:initials``. They are display text; the edit itself is
|
|
493
494
|
attributed to the signed-in user. Without an ``author`` the
|
|
494
495
|
comment's author is the session's name (``Document.user_name``,
|
|
495
|
-
else "Athena"). Use
|
|
496
|
+
else the signed-in user, else "Athena"). Use
|
|
497
|
+
:meth:`Document.add_comment` to thread a
|
|
496
498
|
run-anchored target — this method creates an unanchored comment.
|
|
497
499
|
"""
|
|
498
500
|
# python-docx 1.x routes ``text`` / ``author`` / ``initials``
|
|
@@ -853,7 +853,8 @@ class Document:
|
|
|
853
853
|
``initials`` as Word's ``w:author`` / ``w:initials`` (display
|
|
854
854
|
text; the edit itself is attributed to the signed-in user). Without
|
|
855
855
|
an ``author`` its author is the session's name
|
|
856
|
-
(:attr:`user_name`, else "Athena"). The
|
|
856
|
+
(:attr:`user_name`, else the signed-in user, else "Athena"). The
|
|
857
|
+
runs must be co-located in
|
|
857
858
|
a single block (Word can't anchor a comment to disjoint blocks); if
|
|
858
859
|
they span multiple blocks the comment is created unanchored.
|
|
859
860
|
"""
|
|
@@ -11,6 +11,10 @@ from docx._batching import run_sync
|
|
|
11
11
|
from docx._run_order import forget_paragraph, register_run
|
|
12
12
|
from docx._tracked import tracking
|
|
13
13
|
|
|
14
|
+
#: The session attribute ``Paragraph.delete`` bumps, after which every
|
|
15
|
+
#: paragraph handle of the session reads its list number again.
|
|
16
|
+
_NUMBERING_GENERATION_ATTR = "_docx_numbering_generation"
|
|
17
|
+
|
|
14
18
|
if TYPE_CHECKING:
|
|
15
19
|
from docx._references import AssetReference
|
|
16
20
|
from docx.bookmarks import Bookmark
|
|
@@ -675,8 +679,10 @@ class Paragraph:
|
|
|
675
679
|
)
|
|
676
680
|
# We just replaced the entire paragraph contents with ``value``;
|
|
677
681
|
# the new text-address length is simply ``len(value)``. With tracking
|
|
678
|
-
# on the old
|
|
679
|
-
|
|
682
|
+
# on docx-studio keeps the words the old and new text share and marks
|
|
683
|
+
# only the rest, so only the server knows the length: read it back
|
|
684
|
+
# before the next edit that needs it (``docx._tracked``).
|
|
685
|
+
self._text_len = None if tracked else len(value)
|
|
680
686
|
# The runs of the paragraph are gone, as in python-docx.
|
|
681
687
|
forget_paragraph(self)
|
|
682
688
|
# Content changed — drop the prefetched snapshot so a follow-up
|
|
@@ -2141,8 +2147,77 @@ class Paragraph:
|
|
|
2141
2147
|
)
|
|
2142
2148
|
self._list_info_cache = None
|
|
2143
2149
|
|
|
2150
|
+
@athena_extension(
|
|
2151
|
+
issue=33,
|
|
2152
|
+
since="0.30.0",
|
|
2153
|
+
description="Paragraph.delete — delete the whole paragraph, as a tracked deletion with track_revisions.",
|
|
2154
|
+
)
|
|
2155
|
+
def delete(self) -> None:
|
|
2156
|
+
"""Delete this paragraph from the document, its paragraph mark included.
|
|
2157
|
+
|
|
2158
|
+
python-docx has no paragraph delete (issue #33); code written for it
|
|
2159
|
+
removes the element, ``p._element.getparent().remove(p._element)``,
|
|
2160
|
+
which this SDK cannot reach. ``paragraph.delete()`` does that here::
|
|
2161
|
+
|
|
2162
|
+
for p in doc.paragraphs:
|
|
2163
|
+
if p.text.startswith("Forfeiture of Rights"):
|
|
2164
|
+
p.delete()
|
|
2165
|
+
|
|
2166
|
+
With tracking off the paragraph goes. With ``track_revisions`` on it
|
|
2167
|
+
is Word's tracked deletion of a whole paragraph: all its content, its
|
|
2168
|
+
cross-reference and other fields, links and note references included,
|
|
2169
|
+
and its paragraph mark, one change by the signed-in user. Accept All
|
|
2170
|
+
removes the paragraph and the numbered paragraphs after it number on;
|
|
2171
|
+
Reject All gives it back as it was. Setting ``p.text = ""`` instead
|
|
2172
|
+
leaves an empty (still numbered) paragraph behind.
|
|
2173
|
+
|
|
2174
|
+
The delete goes in a request of its own, after the edits buffered
|
|
2175
|
+
before it, so a refused one takes none of them down.
|
|
2176
|
+
|
|
2177
|
+
Raises:
|
|
2178
|
+
DocxError: docx-studio refused the delete, and changed nothing:
|
|
2179
|
+
``ParagraphDeleteRefused`` for the document's last paragraph
|
|
2180
|
+
(Word never deletes its mark), one that ends a section, the
|
|
2181
|
+
only paragraph of a table cell or content control, one holding
|
|
2182
|
+
part of a field that spans paragraphs, and one in a header,
|
|
2183
|
+
footer, comment or text box; with tracking on,
|
|
2184
|
+
``TrackedChangesUnsupported`` for one in a table cell or holding
|
|
2185
|
+
a page break, a content control, a shape or an equation.
|
|
2186
|
+
"""
|
|
2187
|
+
from docx.commands import DeleteParagraph
|
|
2188
|
+
|
|
2189
|
+
self._adopt_cell_paragraph()
|
|
2190
|
+
run_sync(self._session.save())
|
|
2191
|
+
run_sync(self._session.send_command(DeleteParagraph(block_id=self._node_id)))
|
|
2192
|
+
# The template's REF paragraphs are restored on export by their body
|
|
2193
|
+
# index (``docx._postproc``), which this delete may have shifted.
|
|
2194
|
+
post_export_ops: object = getattr(self._session, "_post_export_ops", None)
|
|
2195
|
+
forget = getattr(post_export_ops, "forget_captured_refs", None)
|
|
2196
|
+
if callable(forget):
|
|
2197
|
+
forget()
|
|
2198
|
+
# Every handle's list number is read again: the items after this one renumber.
|
|
2199
|
+
generation: object = getattr(self._session, _NUMBERING_GENERATION_ATTR, 0)
|
|
2200
|
+
next_generation = (generation if isinstance(generation, int) else 0) + 1
|
|
2201
|
+
try:
|
|
2202
|
+
setattr(self._session, _NUMBERING_GENERATION_ATTR, next_generation)
|
|
2203
|
+
except AttributeError: # a session that takes no new attribute
|
|
2204
|
+
pass
|
|
2205
|
+
self._text_len = None
|
|
2206
|
+
forget_paragraph(self)
|
|
2207
|
+
self._invalidate_node_info()
|
|
2208
|
+
self._list_info_cache = None
|
|
2209
|
+
|
|
2144
2210
|
def _list_info(self) -> dict | None:
|
|
2145
|
-
"""Cache-then-fetch the numbering record for this paragraph.
|
|
2211
|
+
"""Cache-then-fetch the numbering record for this paragraph.
|
|
2212
|
+
|
|
2213
|
+
The cache holds until a paragraph of the session is deleted
|
|
2214
|
+
(:meth:`delete` bumps the session's numbering generation): the list
|
|
2215
|
+
items after it number again, so every handle reads its number anew.
|
|
2216
|
+
"""
|
|
2217
|
+
generation: object = getattr(self._session, _NUMBERING_GENERATION_ATTR, 0)
|
|
2218
|
+
if getattr(self, "_list_info_generation", 0) != generation:
|
|
2219
|
+
self._list_info_cache = None
|
|
2220
|
+
self._list_info_generation = generation
|
|
2146
2221
|
cache = getattr(self, "_list_info_cache", None)
|
|
2147
2222
|
if cache is not None:
|
|
2148
2223
|
return cache or None
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "athena-python-docx"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.30.0"
|
|
8
8
|
description = "Drop-in replacement for python-docx that connects to Athena's DOCX Studio collaborative document stack"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -173,6 +173,7 @@
|
|
|
173
173
|
"fixture-bookmarks-internal-links",
|
|
174
174
|
"fixture-breaks-inline",
|
|
175
175
|
"fixture-breaks-tabs",
|
|
176
|
+
"fixture-character-style-toggles",
|
|
176
177
|
"fixture-chart-column",
|
|
177
178
|
"fixture-cjk-grid-theme-colors",
|
|
178
179
|
"fixture-comments-links",
|
|
@@ -253,10 +254,5 @@
|
|
|
253
254
|
"rw16_header_footer_tables",
|
|
254
255
|
"rw17_header_letterhead_filled"
|
|
255
256
|
],
|
|
256
|
-
"gaps": [
|
|
257
|
-
"fixture-headers-tabs-wrapped::reads::sections.header.paragraphs",
|
|
258
|
-
"fixture-tables-content-controls::reads::tables.cell_format",
|
|
259
|
-
"fixture-tables-content-controls::reads::tables.cells",
|
|
260
|
-
"fixture-tables-content-controls::reads::tables.rows"
|
|
261
|
-
]
|
|
257
|
+
"gaps": []
|
|
262
258
|
}
|
{athena_python_docx-0.29.0 → athena_python_docx-0.30.0}/tests/test_athena_extensions_registry.py
RENAMED
|
@@ -113,6 +113,7 @@ _EXPECTED_LOCATIONS: set[str] = {
|
|
|
113
113
|
"docx.text.paragraph.Paragraph.list_format",
|
|
114
114
|
"docx.text.paragraph.Paragraph.list_number",
|
|
115
115
|
"docx.text.paragraph.Paragraph.restart_numbering",
|
|
116
|
+
"docx.text.paragraph.Paragraph.delete",
|
|
116
117
|
# Run methods.
|
|
117
118
|
"docx.text.run.Run.add_field",
|
|
118
119
|
"docx.text.run.Run.add_footnote",
|
|
@@ -89,7 +89,7 @@ def test_path_proxy_walks_dotted_path() -> None:
|
|
|
89
89
|
assert body["client"] == {
|
|
90
90
|
"type": "python-sdk",
|
|
91
91
|
"version": SDK_VERSION,
|
|
92
|
-
"capabilities": ["trackedAuthoring"],
|
|
92
|
+
"capabilities": ["trackedAuthoring", "trackedMinimalParagraphText"],
|
|
93
93
|
}
|
|
94
94
|
assert body["return"] == {"snapshot": False}
|
|
95
95
|
assert body["commands"] == [
|