athena-python-docx 0.23.0__tar.gz → 0.24.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.23.0 → athena_python_docx-0.24.0}/PKG-INFO +1 -1
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/__init__.py +1 -1
- athena_python_docx-0.24.0/docx/_run_order.py +217 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/commands.py +19 -2
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/shape.py +89 -12
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/paragraph.py +9 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/run.py +106 -50
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/pyproject.toml +1 -1
- athena_python_docx-0.24.0/tests/test_inline_shape_alt_text.py +230 -0
- athena_python_docx-0.24.0/tests/test_run_identity.py +306 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_run_mark_inheritance.py +76 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_wire_contract.py +6 -4
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/.gitignore +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/AGENTS.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/CLAUDE.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/README.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_citations.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_http.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_postproc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_references.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/api.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/charts.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/client.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/comments.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/document.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/errors.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/fields.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/math.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/section.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/session.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/settings.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/shared.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/table.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/toc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/docx/typing.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_athena_extension_creates_session_open.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_fastpath_runs.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_inner_run_guard.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_citations.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_postproc_ref_restore.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_run_add_picture_anchor.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/tests/test_zod_wire_contract.py +0 -0
- {athena_python_docx-0.23.0 → athena_python_docx-0.24.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.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>
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Run order of a paragraph, as ``Paragraph.add_run`` created its runs.
|
|
2
|
+
|
|
3
|
+
A picture takes no text offset, so two runs can end at the same offset:
|
|
4
|
+
``r1 = p.add_run("A"); r2 = p.add_run(); r2.add_picture(img)`` puts ``r2`` and
|
|
5
|
+
its picture at offset 1, where ``r1`` ends. The offset alone cannot tell the
|
|
6
|
+
server whether content for ``r1`` goes before or after that picture. The SDK
|
|
7
|
+
knows: ``add_run`` appends each run to the end of its paragraph.
|
|
8
|
+
|
|
9
|
+
This module keeps a record of each such run (its range and the pictures that
|
|
10
|
+
its ``add_picture`` added), in creation order, and gives:
|
|
11
|
+
|
|
12
|
+
- the run identity of a run-end insert (:func:`run_ref`): the first picture
|
|
13
|
+
that a later run holds at the same offset (for a read segment that ends
|
|
14
|
+
inside its run, also the run's own picture there). The server puts the
|
|
15
|
+
content in front of it; without it, after the pictures at the offset.
|
|
16
|
+
- current ranges: when a run grows or shrinks, its pictures and the runs after
|
|
17
|
+
it move (:func:`note_length_change`), and so do the live run proxies. A
|
|
18
|
+
replace cuts every record that it touches.
|
|
19
|
+
|
|
20
|
+
A record lives as long as its paragraph proxy, not as long as its run proxy,
|
|
21
|
+
so ``p.add_run().add_picture(img)`` keeps the picture's place. The records of
|
|
22
|
+
every paragraph proxy of one block (``doc.paragraphs`` makes new ones) are one
|
|
23
|
+
order. A read run (``paragraph.runs``) stands for the recorded run that holds
|
|
24
|
+
its last character; a read run over text that no recorded run holds counts as
|
|
25
|
+
a run before all of them. The order lives in the SDK process only; the
|
|
26
|
+
document stores none of it.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import itertools
|
|
32
|
+
import weakref
|
|
33
|
+
from dataclasses import dataclass, field
|
|
34
|
+
from typing import TYPE_CHECKING, Any
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from docx.text.run import Run
|
|
38
|
+
|
|
39
|
+
_SEQ = itertools.count()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(eq=False)
|
|
43
|
+
class RunRecord:
|
|
44
|
+
"""One run that ``add_run`` created."""
|
|
45
|
+
|
|
46
|
+
seq: int
|
|
47
|
+
range: tuple[int, int]
|
|
48
|
+
run: "weakref.ref[Run]"
|
|
49
|
+
# ``(picture id, offset)`` of each picture that the run's ``add_picture`` added.
|
|
50
|
+
pictures: list[tuple[str, int]] = field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Paragraph proxy -> the records of the runs its ``add_run`` created. A record
|
|
54
|
+
# holds no reference to the paragraph or session, so an entry goes with its
|
|
55
|
+
# paragraph proxy. Keyed by the proxy, not by its id: the first flush moves a
|
|
56
|
+
# new paragraph from its client id to the server id, and the runs created
|
|
57
|
+
# before that keep the client id.
|
|
58
|
+
_ORDERS: "weakref.WeakKeyDictionary[Any, list[RunRecord]]" = weakref.WeakKeyDictionary()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _records_of(run: "Run") -> list[RunRecord]:
|
|
62
|
+
paragraph = getattr(run, "_paragraph", None)
|
|
63
|
+
ids = {run._block_id}
|
|
64
|
+
if paragraph is not None:
|
|
65
|
+
ids.add(paragraph._node_id)
|
|
66
|
+
records: list[RunRecord] = []
|
|
67
|
+
for owner, owner_records in list(_ORDERS.items()):
|
|
68
|
+
if owner is paragraph or (owner._session is run._session and owner._node_id in ids):
|
|
69
|
+
records.extend(owner_records)
|
|
70
|
+
records.sort(key=lambda record: record.seq)
|
|
71
|
+
return records
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def register_run(run: "Run") -> None:
|
|
75
|
+
"""Record ``run`` as the last run of its paragraph (``Paragraph.add_run``)."""
|
|
76
|
+
record = RunRecord(seq=next(_SEQ), range=run._range, run=weakref.ref(run))
|
|
77
|
+
_ORDERS.setdefault(run._paragraph, []).append(record)
|
|
78
|
+
run._run_record = record
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def forget_paragraph(paragraph: Any) -> None:
|
|
82
|
+
"""Drop the order of a paragraph whose runs are gone (``Paragraph.text = ...``)."""
|
|
83
|
+
for owner in list(_ORDERS.keys()):
|
|
84
|
+
if owner is paragraph or (owner._session is paragraph._session and owner._node_id == paragraph._node_id):
|
|
85
|
+
_ORDERS.pop(owner, None)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _place(
|
|
89
|
+
run: "Run", span: tuple[int, int], records: list[RunRecord] | None = None
|
|
90
|
+
) -> tuple[RunRecord | None, list[RunRecord]]:
|
|
91
|
+
"""The record of ``run`` (over ``span``), if any, and the records after it."""
|
|
92
|
+
if records is None:
|
|
93
|
+
records = _records_of(run)
|
|
94
|
+
# The run itself, or the text that its ``add_text`` returned.
|
|
95
|
+
own = getattr(run, "_run_record", None) or getattr(run, "_owner_record", None)
|
|
96
|
+
for index, record in enumerate(records):
|
|
97
|
+
if record is own:
|
|
98
|
+
return record, records[index + 1 :]
|
|
99
|
+
# ``paragraph.runs`` makes a new proxy of a kept run: over the same range,
|
|
100
|
+
# or over a part of it (a read splits a run at a tab, a break or a change
|
|
101
|
+
# of format). The proxy stands for the run that holds its last character.
|
|
102
|
+
if span[0] != span[1]:
|
|
103
|
+
last = span[1] - 1
|
|
104
|
+
for index, record in enumerate(records):
|
|
105
|
+
if record.range[0] <= last < record.range[1]:
|
|
106
|
+
return record, records[index + 1 :]
|
|
107
|
+
return None, records
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _set_range(record: RunRecord, value: tuple[int, int]) -> None:
|
|
111
|
+
record.range = value
|
|
112
|
+
proxy = record.run()
|
|
113
|
+
if proxy is not None:
|
|
114
|
+
proxy._range = value
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def note_length_change(
|
|
118
|
+
run: "Run",
|
|
119
|
+
at: int,
|
|
120
|
+
delta: int,
|
|
121
|
+
*,
|
|
122
|
+
replaced: tuple[int, int] | None = None,
|
|
123
|
+
before: str | None = None,
|
|
124
|
+
) -> None:
|
|
125
|
+
"""``run`` (already over its new range) changed its text by ``delta`` units.
|
|
126
|
+
|
|
127
|
+
Without ``replaced``: an insert of ``delta`` units at ``at`` (the end of
|
|
128
|
+
``run``), in front of the picture ``before`` when the command named one
|
|
129
|
+
(else after the pictures at ``at``). With ``replaced``: ``Run.text``
|
|
130
|
+
replaced the old range ``replaced``; the server keeps the pictures at its
|
|
131
|
+
start and end and removes the ones inside.
|
|
132
|
+
|
|
133
|
+
The text belongs to the record of ``run`` (see :func:`_place`). Every
|
|
134
|
+
record that the replaced range touches is cut; the records and pictures
|
|
135
|
+
after the change move.
|
|
136
|
+
"""
|
|
137
|
+
if delta == 0 and replaced is None:
|
|
138
|
+
return
|
|
139
|
+
records = _records_of(run)
|
|
140
|
+
if replaced is None:
|
|
141
|
+
start = end = at
|
|
142
|
+
inserted = delta
|
|
143
|
+
old_span = (run._range[0], run._range[1] - delta)
|
|
144
|
+
else:
|
|
145
|
+
start, end = replaced
|
|
146
|
+
inserted = (end - start) + delta
|
|
147
|
+
old_span = replaced
|
|
148
|
+
owner = _place(run, old_span, records)[0]
|
|
149
|
+
owner_index = records.index(owner) if owner is not None else -1
|
|
150
|
+
removed = end - start
|
|
151
|
+
|
|
152
|
+
def cut(x: int) -> int:
|
|
153
|
+
return x if x <= start else start if x < end else x - removed
|
|
154
|
+
|
|
155
|
+
# The pictures at ``at`` that an insert goes in front of: ``before`` and
|
|
156
|
+
# the ones after it, in document order (records in order, then the
|
|
157
|
+
# pictures of each record in order).
|
|
158
|
+
moved_at: set[str] = set()
|
|
159
|
+
if replaced is None and before is not None:
|
|
160
|
+
order = [pid for record in records for pid, off in record.pictures if off == at]
|
|
161
|
+
if before in order:
|
|
162
|
+
moved_at = set(order[order.index(before) :])
|
|
163
|
+
|
|
164
|
+
for index, record in enumerate(records):
|
|
165
|
+
rec_start, rec_end = cut(record.range[0]), cut(record.range[1])
|
|
166
|
+
if record is owner:
|
|
167
|
+
rec_end += inserted
|
|
168
|
+
elif index > owner_index and rec_start >= start:
|
|
169
|
+
rec_start, rec_end = rec_start + inserted, rec_end + inserted
|
|
170
|
+
_set_range(record, (rec_start, rec_end))
|
|
171
|
+
pictures: list[tuple[str, int]] = []
|
|
172
|
+
for pid, off in record.pictures:
|
|
173
|
+
if replaced is None:
|
|
174
|
+
pictures.append((pid, off + delta if off > at or pid in moved_at else off))
|
|
175
|
+
elif off <= start:
|
|
176
|
+
pictures.append((pid, off))
|
|
177
|
+
elif off >= end:
|
|
178
|
+
pictures.append((pid, off + delta))
|
|
179
|
+
# The moves keep document order; a stable sort by offset keeps it so.
|
|
180
|
+
pictures.sort(key=lambda item: item[1])
|
|
181
|
+
record.pictures = pictures
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def note_picture(run: "Run", picture_id: str, offset: int, *, before: str | None = None) -> None:
|
|
185
|
+
"""``run.add_picture`` put the picture ``picture_id`` at ``offset``, in front of ``before``.
|
|
186
|
+
|
|
187
|
+
A record keeps its pictures in document order: the new one goes in front
|
|
188
|
+
of ``before``, else after the pictures at ``offset`` and before the ones
|
|
189
|
+
after it (the server puts a picture after the pictures at its offset).
|
|
190
|
+
"""
|
|
191
|
+
record = _place(run, run._range)[0]
|
|
192
|
+
if record is None:
|
|
193
|
+
return
|
|
194
|
+
ids = [pid for pid, _ in record.pictures]
|
|
195
|
+
if before in ids:
|
|
196
|
+
index = ids.index(before)
|
|
197
|
+
else:
|
|
198
|
+
index = next((i for i, (_, off) in enumerate(record.pictures) if off > offset), len(ids))
|
|
199
|
+
record.pictures.insert(index, (picture_id, offset))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def run_ref(run: "Run") -> dict[str, str] | None:
|
|
203
|
+
"""``{"beforeImageId": id}``: the picture that an insert at the end of ``run`` goes in front of.
|
|
204
|
+
|
|
205
|
+
The first picture of a later run where ``run`` ends. A read segment that
|
|
206
|
+
ends inside its run (a picture of the run between two of its texts) also
|
|
207
|
+
puts the insert in front of the run's own picture there, right after the
|
|
208
|
+
segment's text.
|
|
209
|
+
"""
|
|
210
|
+
end = run._range[1]
|
|
211
|
+
record, later = _place(run, run._range)
|
|
212
|
+
candidates = ([record] if record is not None and end < record.range[1] else []) + later
|
|
213
|
+
for candidate in candidates:
|
|
214
|
+
for picture_id, offset in candidate.pictures:
|
|
215
|
+
if offset == end:
|
|
216
|
+
return {"beforeImageId": picture_id}
|
|
217
|
+
return None
|
|
@@ -109,12 +109,19 @@ class CreateTable(Command):
|
|
|
109
109
|
client_node_id: str | None = None
|
|
110
110
|
|
|
111
111
|
|
|
112
|
+
# Run identity of a run-end insert (``Run.add_text`` / ``add_tab`` /
|
|
113
|
+
# ``add_break`` / ``add_picture``, ``Run.text`` on an empty run):
|
|
114
|
+
# ``{"beforeImageId": <picture id>}``, the first picture that a later run
|
|
115
|
+
# holds at the same offset (see ``docx._run_order``). The server puts the
|
|
116
|
+
# content in front of it. ``None`` (not sent): after the pictures there.
|
|
117
|
+
# ``Insert``, ``InsertTab`` and ``InsertLineBreak`` carry it too.
|
|
112
118
|
@dataclass
|
|
113
119
|
class CreateImage(Command):
|
|
114
120
|
src: str
|
|
115
121
|
size: dict[str, Any]
|
|
116
122
|
at: dict[str, Any]
|
|
117
123
|
client_node_id: str | None = None
|
|
124
|
+
run: dict[str, Any] | None = None
|
|
118
125
|
|
|
119
126
|
|
|
120
127
|
@dataclass
|
|
@@ -142,6 +149,7 @@ class Insert(Command):
|
|
|
142
149
|
inherit_marks: bool | None = None
|
|
143
150
|
placement: str | None = None
|
|
144
151
|
content: dict[str, Any] | None = None
|
|
152
|
+
run: dict[str, Any] | None = None
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
@dataclass
|
|
@@ -181,12 +189,14 @@ class Replace(Command):
|
|
|
181
189
|
class InsertLineBreak(Command):
|
|
182
190
|
block_id: str
|
|
183
191
|
offset: int
|
|
192
|
+
run: dict[str, Any] | None = None
|
|
184
193
|
|
|
185
194
|
|
|
186
195
|
@dataclass
|
|
187
196
|
class InsertTab(Command):
|
|
188
197
|
block_id: str
|
|
189
198
|
offset: int
|
|
199
|
+
run: dict[str, Any] | None = None
|
|
190
200
|
|
|
191
201
|
|
|
192
202
|
@dataclass
|
|
@@ -490,10 +500,15 @@ class SetImageSize(Command):
|
|
|
490
500
|
class SetImageAltText(Command):
|
|
491
501
|
"""Set alt-text on an inline image. Mirrors DOCX Studio's
|
|
492
502
|
``doc.images.setAltText``. Used by accessibility flows that need
|
|
493
|
-
a text alternative for screen readers.
|
|
503
|
+
a text alternative for screen readers.
|
|
504
|
+
|
|
505
|
+
``alt_text`` is Word's description (``wp:docPr/@descr``). ``title`` is
|
|
506
|
+
Word's title (``wp:docPr/@title``); ``None`` leaves it unchanged, and an
|
|
507
|
+
older docx-studio ignores the field."""
|
|
494
508
|
|
|
495
509
|
image_id: str
|
|
496
510
|
alt_text: str
|
|
511
|
+
title: str | None = None
|
|
497
512
|
|
|
498
513
|
|
|
499
514
|
@dataclass
|
|
@@ -551,7 +566,9 @@ class GetNode(Command):
|
|
|
551
566
|
|
|
552
567
|
@dataclass
|
|
553
568
|
class ImagesList(Command):
|
|
554
|
-
|
|
569
|
+
# ``False`` leaves out each picture's ``src`` (a data URI can be MBs); an
|
|
570
|
+
# older docx-studio ignores the field and sends ``src``.
|
|
571
|
+
include_src: bool | None = None
|
|
555
572
|
|
|
556
573
|
|
|
557
574
|
@dataclass
|
|
@@ -65,6 +65,19 @@ def _strip_data_uri(src: str) -> tuple[bytes, str | None]:
|
|
|
65
65
|
return b"", mime
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
def _picture_id_parts(node_id: str) -> tuple[str, str, str | None]:
|
|
69
|
+
"""``(paraId, fingerprint, persisted id)`` of a picture id.
|
|
70
|
+
|
|
71
|
+
A picture id is ``<paraId>:<index>:<fingerprint>``, with a fourth part
|
|
72
|
+
``:<persisted id>`` when the room stores one; an older docx-studio gives
|
|
73
|
+
only ``<paraId>`` or ``<paraId>:<index>``.
|
|
74
|
+
"""
|
|
75
|
+
parts = node_id.split(":")
|
|
76
|
+
fingerprint = parts[2] if len(parts) > 2 else ""
|
|
77
|
+
persisted = parts[3] if len(parts) > 3 else None
|
|
78
|
+
return parts[0], fingerprint, persisted
|
|
79
|
+
|
|
80
|
+
|
|
68
81
|
class InlineShape:
|
|
69
82
|
"""An inline image/shape in the document."""
|
|
70
83
|
|
|
@@ -177,15 +190,75 @@ class InlineShape:
|
|
|
177
190
|
@alt_text.setter
|
|
178
191
|
@athena_extension(issue="PR#1530", description="InlineShape.alt_text setter.")
|
|
179
192
|
def alt_text(self, value: str | None) -> None:
|
|
193
|
+
text = "" if value is None else str(value)
|
|
194
|
+
if self._can_address(stacklevel=3):
|
|
195
|
+
self._send_alt_text(alt_text=text, title=None)
|
|
196
|
+
self._info["altText"] = text
|
|
197
|
+
|
|
198
|
+
def _can_address(self, *, stacklevel: int) -> bool:
|
|
199
|
+
"""``False`` (with a warning) for a shape that has no id.
|
|
200
|
+
|
|
201
|
+
A listed picture on an older docx-studio, whose ``ImagesList`` sends
|
|
202
|
+
no ``nodeId``, cannot be addressed, and an empty ``imageId`` fails the
|
|
203
|
+
whole batch there. The setter then sends nothing and keeps the old
|
|
204
|
+
value, so the shape does not report a change that the document does
|
|
205
|
+
not have.
|
|
206
|
+
"""
|
|
207
|
+
from docx.errors import DocxUnsupportedCommandWarning
|
|
208
|
+
|
|
209
|
+
if self._node_id:
|
|
210
|
+
return True
|
|
211
|
+
warnings.warn(
|
|
212
|
+
"InlineShape alt text / title / decorative was not set: this picture has "
|
|
213
|
+
"no id. Read the shape again from doc.inline_shapes after "
|
|
214
|
+
"docx-studio is updated.",
|
|
215
|
+
DocxUnsupportedCommandWarning,
|
|
216
|
+
stacklevel=stacklevel + 1,
|
|
217
|
+
)
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
def _send_alt_text(self, *, alt_text: str, title: str | None) -> None:
|
|
180
221
|
from docx.commands import SetImageAltText
|
|
181
222
|
|
|
182
|
-
text = "" if value is None else str(value)
|
|
183
223
|
run_sync(
|
|
184
224
|
self._session.send_command(
|
|
185
|
-
SetImageAltText(image_id=self._node_id, alt_text=
|
|
225
|
+
SetImageAltText(image_id=self._node_id, alt_text=alt_text, title=title),
|
|
186
226
|
),
|
|
187
227
|
)
|
|
188
|
-
|
|
228
|
+
|
|
229
|
+
def _stored_alt_text(self) -> str:
|
|
230
|
+
"""The description that the document stores for this picture now.
|
|
231
|
+
|
|
232
|
+
Another shape for the same picture can change the description after
|
|
233
|
+
this shape read it. ``ImagesList`` gives the current value, without
|
|
234
|
+
the image data; the cached value is the fallback when the list does
|
|
235
|
+
not name the picture (an older docx-studio). The read flushes pending
|
|
236
|
+
commands first, so a client id is the real id after it.
|
|
237
|
+
"""
|
|
238
|
+
rows = InlineShapes(session=self._session)._items(include_src=False)
|
|
239
|
+
node_id = self._node_id
|
|
240
|
+
para_id, fingerprint, persisted = _picture_id_parts(node_id)
|
|
241
|
+
same: list[dict] = []
|
|
242
|
+
for row in rows:
|
|
243
|
+
row_id = str(row.get("nodeId") or "")
|
|
244
|
+
if row_id == node_id:
|
|
245
|
+
same = [row]
|
|
246
|
+
break
|
|
247
|
+
row_para, row_fingerprint, row_persisted = _picture_id_parts(row_id)
|
|
248
|
+
# A persisted id names one picture, in any paragraph and position.
|
|
249
|
+
if persisted is not None and row_persisted is not None:
|
|
250
|
+
if row_persisted == persisted:
|
|
251
|
+
same = [row]
|
|
252
|
+
break
|
|
253
|
+
continue
|
|
254
|
+
# A room without persisted ids (an older editor removed them):
|
|
255
|
+
# the paragraph and the fingerprint, as the server does.
|
|
256
|
+
if row_para != para_id:
|
|
257
|
+
continue
|
|
258
|
+
if ":" not in node_id or (fingerprint and row_fingerprint == fingerprint):
|
|
259
|
+
same.append(row)
|
|
260
|
+
stored = same[0].get("altText") if len(same) == 1 else None
|
|
261
|
+
return stored if isinstance(stored, str) else self.alt_text
|
|
189
262
|
|
|
190
263
|
@property
|
|
191
264
|
@athena_extension(issue="PR#1530", description="InlineShape.title — image title.")
|
|
@@ -202,14 +275,15 @@ class InlineShape:
|
|
|
202
275
|
@title.setter
|
|
203
276
|
@athena_extension(issue="PR#1530", description="InlineShape.title setter.")
|
|
204
277
|
def title(self, value: str | None) -> None:
|
|
205
|
-
from docx.commands import SetImageAltText
|
|
206
|
-
|
|
207
278
|
text = "" if value is None else str(value)
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
279
|
+
if not self._can_address(stacklevel=3):
|
|
280
|
+
return
|
|
281
|
+
# The command always carries the description: an older docx-studio
|
|
282
|
+
# requires ``altText`` and ignores ``title``. Sending the stored
|
|
283
|
+
# description keeps it; before, the title text replaced it.
|
|
284
|
+
alt_text = self._stored_alt_text()
|
|
285
|
+
self._send_alt_text(alt_text=alt_text, title=text)
|
|
286
|
+
self._info["altText"] = alt_text
|
|
213
287
|
self._info["title"] = text
|
|
214
288
|
|
|
215
289
|
@property
|
|
@@ -228,6 +302,8 @@ class InlineShape:
|
|
|
228
302
|
def decorative(self, value: bool) -> None:
|
|
229
303
|
from docx.commands import SetImageDecorative
|
|
230
304
|
|
|
305
|
+
if not self._can_address(stacklevel=3):
|
|
306
|
+
return
|
|
231
307
|
run_sync(
|
|
232
308
|
self._session.send_command(
|
|
233
309
|
SetImageDecorative(image_id=self._node_id, decorative=bool(value)),
|
|
@@ -283,8 +359,9 @@ class InlineShapes:
|
|
|
283
359
|
def __init__(self, *, session: "Session") -> None:
|
|
284
360
|
self._session: "Session" = session
|
|
285
361
|
|
|
286
|
-
def _items(self) -> list[dict]:
|
|
287
|
-
|
|
362
|
+
def _items(self, *, include_src: bool = True) -> list[dict]:
|
|
363
|
+
params: dict = {} if include_src else {"includeSrc": False}
|
|
364
|
+
info: object = run_sync(self._session.doc.images.list(params))
|
|
288
365
|
if isinstance(info, dict):
|
|
289
366
|
items: object = info.get("items") or info.get("images") or []
|
|
290
367
|
if isinstance(items, list):
|
|
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
7
7
|
|
|
8
8
|
from docx._athena_extension import athena_extension
|
|
9
9
|
from docx._batching import run_sync
|
|
10
|
+
from docx._run_order import forget_paragraph, register_run
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING:
|
|
12
13
|
from docx._references import AssetReference
|
|
@@ -431,6 +432,8 @@ class Paragraph:
|
|
|
431
432
|
# We just replaced the entire paragraph contents with ``value``;
|
|
432
433
|
# the new text-address length is simply ``len(value)``.
|
|
433
434
|
self._text_len = len(value)
|
|
435
|
+
# The runs of the paragraph are gone, as in python-docx.
|
|
436
|
+
forget_paragraph(self)
|
|
434
437
|
# Content changed — drop the prefetched snapshot so a follow-up
|
|
435
438
|
# ``.text`` / ``.runs`` read reflects the replacement.
|
|
436
439
|
self._invalidate_node_info()
|
|
@@ -1232,6 +1235,12 @@ class Paragraph:
|
|
|
1232
1235
|
in_cell=self._in_cell,
|
|
1233
1236
|
cell_ooxml_address=self._cell_ooxml_address,
|
|
1234
1237
|
)
|
|
1238
|
+
# The paragraph's run order, so a run-end insert at an offset that two
|
|
1239
|
+
# runs share goes to the right run (see ``docx._run_order``).
|
|
1240
|
+
register_run(run_obj)
|
|
1241
|
+
# A new empty run has no formatting of its own yet: its first text
|
|
1242
|
+
# does not take the formatting of the run before it.
|
|
1243
|
+
run_obj._fresh = not text_str
|
|
1235
1244
|
if style is not None:
|
|
1236
1245
|
style_id: str = (
|
|
1237
1246
|
style.style_id if isinstance(style, CharacterStyle) else style
|