athena-python-docx 0.31.0__tar.gz → 0.32.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.31.0 → athena_python_docx-0.32.0}/AGENTS.md +6 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/PKG-INFO +1 -1
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_run_order.py +39 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/commands.py +20 -4
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/drawing/__init__.py +7 -2
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/settings.py +12 -2
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/table.py +33 -19
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/paragraph.py +8 -1
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/run.py +154 -14
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/pyproject.toml +1 -1
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/complex_cases.py +1 -1
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/fake_session.py +2 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +1 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/baseline.json +6 -49
- athena_python_docx-0.32.0/tests/live/fixture_scripts.py +188 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_drawing_image.py +38 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_enum_parity.py +4 -2
- athena_python_docx-0.32.0/tests/test_run_break_inner_content.py +121 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_edges.py +25 -0
- athena_python_docx-0.32.0/tests/test_run_later_runs.py +580 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_settings.py +33 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_table_layout.py +8 -6
- athena_python_docx-0.32.0/tests/test_table_direction.py +102 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/uv.lock +1 -1
- athena_python_docx-0.31.0/tests/live/fixture_scripts.py +0 -68
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/.gitignore +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/CLAUDE.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/README.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_capabilities.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_citations.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_http.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_postproc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_references.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/_tracked.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/api.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/blkcntnr.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/charts.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/client.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/comments.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/document.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/base.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/dml.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/errors.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/fields.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/image/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/image/exceptions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/image/image.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/math.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/section.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/session.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/shape.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/shared.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/styles/_table.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/styles/latent.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/toc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/docx/typing.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fixtures/field_reads.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fixtures/note_reference_reads.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fixtures/ruby_reads.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/fixtures/symbol_reads.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/reader.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/runner.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/sdk_driver.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/stock_driver.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/live/test_live_runner.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_add_section.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_athena_extension_creates_session_open.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_batch_chunking.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_borders_spec.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_fastpath_runs.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_inner_run_guard.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_merge.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_nested_tables.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_paragraphs_listed.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_citations.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_color_format_theme.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_comment_paragraphs.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_comments_first_read.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_content_control_value.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_core_properties.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_empty_hyperlinks.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_export_docx_clean.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_export_rescue_anchors.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_field_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_field_refresh.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_field_runs.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_flushed_write_failures.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_inline_page_break.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_inline_shape_alt_text.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_inline_shape_size.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_inline_shape_type.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_inline_shapes_floating.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_missing_modules.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_nested_table_refused.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_page_break.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_paragraph_delete.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_pdf_export_and_page_renders.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_postproc_ref_restore.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_read_run_ranges.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_repeated_node_read.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_restart_numbering.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_round_trip_smoke_script.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_add_picture_anchor.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_formatting_wire.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_identity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_mark_inheritance.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_table_style_objects.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_text_python_docx.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_sdk_reads_served.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_section_read_lengths.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_formatting_writes.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_metadata_writes.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_names.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_style_tab_stops_read.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_table_anchors.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_table_read_reuse.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_text_control_characters.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_tracked_revisions_offsets.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_uv_lock_version.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.31.0 → athena_python_docx-0.32.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -107,6 +107,12 @@ pinned by focused tests and documented in
|
|
|
107
107
|
`horz_dpi`, `width`, `scaled_dimensions`, …). A picture in a table cell or
|
|
108
108
|
a header has no id to read its image by, so `.image` raises `ValueError`;
|
|
109
109
|
an older docx-studio does not report pictures, so they are not runs there.
|
|
110
|
+
- **A run holding only a page or column break yields `""` from
|
|
111
|
+
`Run.iter_inner_content()`,** as python-docx reads a `w:br` of type `page`
|
|
112
|
+
or `column` as empty text; an empty run (a comment reference's) yields
|
|
113
|
+
nothing. docx-studio's read marks such a run with `break`, and
|
|
114
|
+
`Run.add_break` marks the run it adds one to. Against an older docx-studio,
|
|
115
|
+
which sends no `break`, a re-read run yields nothing.
|
|
110
116
|
- **`Styles.latent_styles`** (`docx.styles.latent.LatentStyles`) reads
|
|
111
117
|
the document's `<w:latentStyles>` (defaults and each `w:lsdException`)
|
|
112
118
|
from docx-studio's `Info` (`includeStyles` → `latentStyles`), as python-docx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.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>
|
|
@@ -332,6 +332,45 @@ def note_picture(run: "Run", picture_id: str, offset: int, *, before: str | None
|
|
|
332
332
|
record.pictures.insert(index, (picture_id, offset))
|
|
333
333
|
|
|
334
334
|
|
|
335
|
+
def read_stamp() -> int:
|
|
336
|
+
"""The moment a read gives its runs (``Paragraph.runs``): a run ``add_run``
|
|
337
|
+
creates after it has a higher ``seq``."""
|
|
338
|
+
return next(_SEQ)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def later_runs_at_end(run: "Run") -> int | None:
|
|
342
|
+
"""How many runs after ``run`` end where it does, by which docx-studio
|
|
343
|
+
tells ``run`` from them (``run.laterRuns``) where the offset cannot: an
|
|
344
|
+
empty run ``add_run()`` made after it, or one of breaks alone, ends there
|
|
345
|
+
too.
|
|
346
|
+
|
|
347
|
+
For a run ``add_run`` created, the runs it created after it; for a run a
|
|
348
|
+
read gave (``Paragraph.runs``), the later runs of that read and the runs
|
|
349
|
+
``add_run`` created since. Each where it ends now, not where it ended at
|
|
350
|
+
the read: a write through a run moves the live proxies (:func:`track_run`),
|
|
351
|
+
as clearing a run of text after a run of a break leaves an empty run that
|
|
352
|
+
ends where the break's run does. A read run holds the next run of its
|
|
353
|
+
read (``_next_read``), so the later ones stay live, and current, while it
|
|
354
|
+
is. None for a run proxy that is neither, which the SDK cannot tell from
|
|
355
|
+
the runs around it.
|
|
356
|
+
"""
|
|
357
|
+
end = run._range[1]
|
|
358
|
+
records = _records_of(run)
|
|
359
|
+
own = getattr(run, "_run_record", None) or getattr(run, "_owner_record", None)
|
|
360
|
+
if own is not None and own in records:
|
|
361
|
+
return sum(1 for other in records[records.index(own) + 1 :] if other.range[1] == end)
|
|
362
|
+
read_seq = getattr(run, "_read_seq", None)
|
|
363
|
+
if read_seq is None:
|
|
364
|
+
return None
|
|
365
|
+
later = 0
|
|
366
|
+
following: Run | None = getattr(run, "_next_read", None)
|
|
367
|
+
while following is not None:
|
|
368
|
+
if following._range[1] == end:
|
|
369
|
+
later += 1
|
|
370
|
+
following = getattr(following, "_next_read", None)
|
|
371
|
+
return later + sum(1 for other in records if other.seq > read_seq and other.range[1] == end)
|
|
372
|
+
|
|
373
|
+
|
|
335
374
|
def ends_last_at_its_end(run: "Run") -> bool:
|
|
336
375
|
"""True when no run ``add_run`` created after ``run`` ends where it does.
|
|
337
376
|
|
|
@@ -223,6 +223,10 @@ class Replace(Command):
|
|
|
223
223
|
# …``), whose own properties docx-studio keeps for the new text; an older
|
|
224
224
|
# docx-studio ignores it.
|
|
225
225
|
whole_run: bool | None = None
|
|
226
|
+
# An empty run's identity among the runs at its place (``{"laterRuns": n}``,
|
|
227
|
+
# as ``Insert.run``), sent to a docx-studio reporting
|
|
228
|
+
# ``capabilities.runIdentity``.
|
|
229
|
+
run: dict[str, Any] | None = None
|
|
226
230
|
|
|
227
231
|
|
|
228
232
|
@dataclass
|
|
@@ -233,13 +237,17 @@ class InsertLineBreak(Command):
|
|
|
233
237
|
# ``True`` gives the break the formatting of the run it ends
|
|
234
238
|
# (``Run.add_break``); an older docx-studio ignores it.
|
|
235
239
|
inherit_marks: bool | None = None
|
|
236
|
-
# ``"column"``: a column break (``Run.add_break(WD_BREAK.COLUMN)``),
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
# break.
|
|
240
|
+
# ``"column"``: a column break (``Run.add_break(WD_BREAK.COLUMN)``),
|
|
241
|
+
# outside the paragraph's text-address space: with ``inline``, at the end
|
|
242
|
+
# of the run, in it; otherwise after the paragraph's content. An older
|
|
243
|
+
# docx-studio ignores it and inserts a line break.
|
|
240
244
|
break_type: str | None = None
|
|
241
245
|
# As ``Insert.run_edge``.
|
|
242
246
|
run_edge: str | None = None
|
|
247
|
+
# ``True`` with ``break_type="column"``: the break at the end of the run,
|
|
248
|
+
# in it, as python-docx writes it. Sent only to a docx-studio reporting
|
|
249
|
+
# ``capabilities.inlineColumnBreak``; an older one ignores it.
|
|
250
|
+
inline: bool | None = None
|
|
243
251
|
|
|
244
252
|
|
|
245
253
|
@dataclass
|
|
@@ -261,6 +269,10 @@ class FormatApply(Command):
|
|
|
261
269
|
# (``run.bold = True``), which docx-studio keeps apart with their new
|
|
262
270
|
# formatting; an older docx-studio ignores it.
|
|
263
271
|
whole_run: bool | None = None
|
|
272
|
+
# The identity of an empty run that holds a page or column break
|
|
273
|
+
# (``{"laterRuns": n}``, as ``Insert.run``): its breaks take the
|
|
274
|
+
# formatting. Sent to a docx-studio reporting ``capabilities.runIdentity``.
|
|
275
|
+
run: dict[str, Any] | None = None
|
|
264
276
|
|
|
265
277
|
|
|
266
278
|
@dataclass
|
|
@@ -725,6 +737,10 @@ class Info(Command):
|
|
|
725
737
|
# ``docProps/core.xml``. An older docx-studio ignores the field, which
|
|
726
738
|
# tells the SDK it has no ``SetCoreProperties``.
|
|
727
739
|
include_core_properties: bool | None = None
|
|
740
|
+
# ``True`` also returns ``settings``: ``evenAndOddHeaders``, the
|
|
741
|
+
# document's ``w:evenAndOddHeaders`` in ``word/settings.xml``. An older
|
|
742
|
+
# docx-studio ignores the field and sends none.
|
|
743
|
+
include_settings: bool | None = None
|
|
728
744
|
|
|
729
745
|
|
|
730
746
|
@dataclass
|
|
@@ -29,9 +29,12 @@ class Drawing:
|
|
|
29
29
|
def has_picture(self) -> bool:
|
|
30
30
|
"""True when `drawing` contains an embedded picture.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
As python-docx: False for a drawing whose graphic is not a picture (a
|
|
33
|
+
chart, a diagram, a group), which docx-studio reports with
|
|
34
|
+
``hasPicture: false``. An older docx-studio reports none, and every
|
|
35
|
+
drawing it reports reads as a picture.
|
|
33
36
|
"""
|
|
34
|
-
return
|
|
37
|
+
return self._info.get("hasPicture") is not False
|
|
35
38
|
|
|
36
39
|
@property
|
|
37
40
|
def image(self) -> "Image":
|
|
@@ -44,6 +47,8 @@ class Drawing:
|
|
|
44
47
|
from docx.image.image import Image
|
|
45
48
|
from docx.shape import _strip_data_uri
|
|
46
49
|
|
|
50
|
+
if not self.has_picture:
|
|
51
|
+
raise ValueError("drawing does not contain a picture")
|
|
47
52
|
image_id = self._info.get("imageId")
|
|
48
53
|
if not isinstance(image_id, str) or not image_id:
|
|
49
54
|
raise ValueError("drawing image cannot be read: docx-studio reported no id for it")
|
|
@@ -4,8 +4,9 @@ Most Word app settings are not surfaced by DOCX Studio, so this proxy is
|
|
|
4
4
|
intentionally minimal. The fields that ARE exposed have one-to-one
|
|
5
5
|
DOCX Studio semantics:
|
|
6
6
|
|
|
7
|
-
* ``odd_and_even_pages_header_footer`` —
|
|
8
|
-
``<w:evenAndOddHeaders/>`` flag
|
|
7
|
+
* ``odd_and_even_pages_header_footer`` — reads the document-level
|
|
8
|
+
``<w:evenAndOddHeaders/>`` flag from ``Info`` (``includeSettings``) and
|
|
9
|
+
toggles it via DOCX Studio 1.8.1's
|
|
9
10
|
``doc.sections.setOddEvenHeadersFooters`` (doc-level despite its
|
|
10
11
|
namespace — see ``commands.SetSectionsOddEvenHeadersFooters``).
|
|
11
12
|
* ``track_revisions`` — alias for :attr:`docx.document.Document.track_revisions`.
|
|
@@ -50,6 +51,15 @@ class Settings:
|
|
|
50
51
|
|
|
51
52
|
@property
|
|
52
53
|
def odd_and_even_pages_header_footer(self) -> bool:
|
|
54
|
+
"""The document's ``w:evenAndOddHeaders`` in ``word/settings.xml``, as
|
|
55
|
+
python-docx reads it (False when absent or off). A docx-studio that
|
|
56
|
+
does not report it (``Info`` without ``settings``) gives the value this
|
|
57
|
+
proxy last set."""
|
|
58
|
+
info: object = run_sync(self._session.doc.info({"includeSettings": True}))
|
|
59
|
+
settings: object = info.get("settings") if isinstance(info, dict) else None
|
|
60
|
+
reported: object = settings.get("evenAndOddHeaders") if isinstance(settings, dict) else None
|
|
61
|
+
if isinstance(reported, bool):
|
|
62
|
+
return reported
|
|
53
63
|
return self._odd_and_even_pages_header_footer
|
|
54
64
|
|
|
55
65
|
@odd_and_even_pages_header_footer.setter
|
|
@@ -23,9 +23,11 @@ class PendingTableClearWarning(UserWarning):
|
|
|
23
23
|
setter is asked to clear a property (``None`` assignment) that
|
|
24
24
|
python-docx 1.x supports but DOCX Studio 1.8 has no clear-op for.
|
|
25
25
|
|
|
26
|
-
Covers: ``Table.alignment /
|
|
26
|
+
Covers: ``Table.alignment / autofit``,
|
|
27
27
|
``_Row.height / height_rule``, ``_Column.width``,
|
|
28
|
-
``_Cell.width / vertical_alignment
|
|
28
|
+
``_Cell.width / vertical_alignment``, and any ``Table.table_direction``
|
|
29
|
+
write to a docx-studio that does not report
|
|
30
|
+
``capabilities.tableDirection`` (one that does writes None too). DOCX Studio's
|
|
29
31
|
``tables.set_layout`` / ``set_row_height`` / ``set_column_width``
|
|
30
32
|
/ ``set_cell_properties`` require explicit values — the wire
|
|
31
33
|
can't represent the python-docx "revert to inherited" intent.
|
|
@@ -1241,36 +1243,48 @@ class Table:
|
|
|
1241
1243
|
)
|
|
1242
1244
|
|
|
1243
1245
|
@property
|
|
1244
|
-
def
|
|
1245
|
-
|
|
1246
|
-
|
|
1246
|
+
def table_direction(self) -> "WD_TABLE_DIRECTION | None":
|
|
1247
|
+
"""The table's ``w:bidiVisual`` as python-docx 1.2.0 reads it: ``True``
|
|
1248
|
+
(right to left), ``False`` (an explicit left to right) or None (none),
|
|
1249
|
+
the ``bool`` python-docx returns behind its ``WD_TABLE_DIRECTION`` hint
|
|
1250
|
+
(``True == WD_TABLE_DIRECTION.RTL``)."""
|
|
1247
1251
|
info: object = run_sync(
|
|
1248
1252
|
self._session.doc.tables.get_properties({"nodeId": self._fresh_node_id()}),
|
|
1249
1253
|
)
|
|
1250
|
-
if isinstance(info, dict)
|
|
1251
|
-
|
|
1254
|
+
direction: object = info.get("direction") if isinstance(info, dict) else None
|
|
1255
|
+
if direction == "rtl":
|
|
1256
|
+
return cast("WD_TABLE_DIRECTION", True)
|
|
1257
|
+
if direction == "ltr":
|
|
1258
|
+
return cast("WD_TABLE_DIRECTION", False)
|
|
1252
1259
|
return None
|
|
1253
1260
|
|
|
1254
|
-
@
|
|
1255
|
-
def
|
|
1261
|
+
@table_direction.setter
|
|
1262
|
+
def table_direction(self, value: "WD_TABLE_DIRECTION | int | str | None") -> None:
|
|
1263
|
+
"""As python-docx 1.2.0: RTL writes ``w:bidiVisual``, LTR writes
|
|
1264
|
+
``w:bidiVisual w:val="0"`` and None removes it. A docx-studio that does
|
|
1265
|
+
not report ``capabilities.tableDirection`` drops the write, so the SDK
|
|
1266
|
+
sends none there and warns (``PendingTableClearWarning``)."""
|
|
1267
|
+
from docx._capabilities import server_takes
|
|
1268
|
+
from docx.commands import NULL
|
|
1256
1269
|
from docx.enum.table import WD_TABLE_DIRECTION
|
|
1257
1270
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1271
|
+
# None goes on the wire as JSON null (``NULL``): a ``None`` field is left off it.
|
|
1272
|
+
wire: object = NULL if value is None else WD_TABLE_DIRECTION._wire(value, "Table.table_direction")
|
|
1273
|
+
if not server_takes(self._session, "tableDirection"):
|
|
1274
|
+
warnings.warn(
|
|
1275
|
+
"Table.table_direction was IGNORED: this DOCX Studio does not write a table's "
|
|
1276
|
+
"direction (w:bidiVisual); the table keeps its previous direction.",
|
|
1277
|
+
PendingTableClearWarning,
|
|
1278
|
+
stacklevel=2,
|
|
1279
|
+
)
|
|
1260
1280
|
return
|
|
1261
|
-
|
|
1262
|
-
# DOCX Studio's setLayout takes ``tableDirection`` (not
|
|
1263
|
-
# ``direction``). Same diagnostic as alignment above —
|
|
1264
|
-
# setTableOptions silently swallowed the field.
|
|
1281
|
+
# DOCX Studio's setLayout takes ``tableDirection`` (not ``direction``).
|
|
1265
1282
|
run_sync(
|
|
1266
1283
|
self._session.doc.tables.set_layout(
|
|
1267
|
-
{"nodeId": self._fresh_node_id(), "tableDirection":
|
|
1284
|
+
{"nodeId": self._fresh_node_id(), "tableDirection": wire},
|
|
1268
1285
|
),
|
|
1269
1286
|
)
|
|
1270
1287
|
|
|
1271
|
-
# python-docx aliases
|
|
1272
|
-
table_direction = direction
|
|
1273
|
-
|
|
1274
1288
|
@property
|
|
1275
1289
|
def autofit(self) -> bool:
|
|
1276
1290
|
info: object = run_sync(
|
|
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
9
9
|
from docx._athena_extension import athena_extension
|
|
10
10
|
from docx._batching import run_sync
|
|
11
11
|
from docx._buffer import writes_unapplied
|
|
12
|
-
from docx._run_order import forget_paragraph, register_run
|
|
12
|
+
from docx._run_order import forget_paragraph, read_stamp, register_run
|
|
13
13
|
from docx._tracked import tracking
|
|
14
14
|
|
|
15
15
|
#: The session attribute ``Paragraph.delete`` bumps, after which every
|
|
@@ -818,6 +818,13 @@ class Paragraph:
|
|
|
818
818
|
# cache for free (avoids a follow-up ``get_node_by_id`` if the
|
|
819
819
|
# caller does ``p.runs[...]; p.add_run(...)``).
|
|
820
820
|
self._text_len = offset
|
|
821
|
+
# Each run holds the next one of this read: docx-studio tells it from
|
|
822
|
+
# the later ones that end where it does when content goes to it, by
|
|
823
|
+
# where they end then (``docx._run_order.later_runs_at_end``).
|
|
824
|
+
stamp = read_stamp()
|
|
825
|
+
for index, run_obj in enumerate(runs):
|
|
826
|
+
run_obj._next_read = runs[index + 1] if index + 1 < len(runs) else None
|
|
827
|
+
run_obj._read_seq = stamp
|
|
821
828
|
return runs
|
|
822
829
|
|
|
823
830
|
@property
|
|
@@ -10,6 +10,7 @@ from docx._batching import run_sync
|
|
|
10
10
|
from docx._capabilities import server_takes
|
|
11
11
|
from docx._run_order import (
|
|
12
12
|
ends_last_at_its_end,
|
|
13
|
+
later_runs_at_end,
|
|
13
14
|
note_length_change,
|
|
14
15
|
note_picture,
|
|
15
16
|
note_tracked_replacement,
|
|
@@ -401,12 +402,47 @@ class Run:
|
|
|
401
402
|
|
|
402
403
|
def _mark_append(self, command: dict) -> dict:
|
|
403
404
|
"""Mark content added at the end of this run as this run's
|
|
404
|
-
(``runEdge: "append"``), which docx-studio keeps one run
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
(``runEdge: "append"``), which docx-studio keeps one run. Where later
|
|
406
|
+
runs end where this one does (an empty run, or one of breaks alone),
|
|
407
|
+
to a docx-studio that reports ``capabilities.runIdentity``, with how
|
|
408
|
+
many (``run.laterRuns``), so the content goes into this run; to an
|
|
409
|
+
older one, only when the offset names it: no later run ends there.
|
|
410
|
+
The server is asked only then. Returns ``command``."""
|
|
411
|
+
later = later_runs_at_end(self)
|
|
412
|
+
if later and server_takes(self._session, "runIdentity"):
|
|
413
|
+
command["runEdge"] = "append"
|
|
414
|
+
command["run"] = {**(command.get("run") or {}), "laterRuns": later}
|
|
415
|
+
elif ends_last_at_its_end(self):
|
|
407
416
|
command["runEdge"] = "append"
|
|
408
417
|
return command
|
|
409
418
|
|
|
419
|
+
def _later_runs(self) -> int | None:
|
|
420
|
+
"""The runs after this one that end where it does, by which a
|
|
421
|
+
docx-studio reporting ``capabilities.runIdentity`` tells this run from
|
|
422
|
+
them (``docx._run_order.later_runs_at_end``); None for an older one, or
|
|
423
|
+
a run the SDK cannot tell from the runs around it."""
|
|
424
|
+
if not server_takes(self._session, "runIdentity"):
|
|
425
|
+
return None
|
|
426
|
+
return later_runs_at_end(self)
|
|
427
|
+
|
|
428
|
+
def _break_run_identity(self) -> int | None:
|
|
429
|
+
"""This empty run's identity (:meth:`_later_runs`) while it holds a
|
|
430
|
+
page or column break, which a whole-run ``FormatApply`` of its
|
|
431
|
+
collapsed range formats, untracked; else None. A column break only in
|
|
432
|
+
a room that reports ``capabilities.inlineColumnBreak``: one imported
|
|
433
|
+
before keeps it as a block after the paragraph, which takes no
|
|
434
|
+
formatting, so the formatting waits for content the run takes. So
|
|
435
|
+
does a break the read says is no node of the paragraph
|
|
436
|
+
(``breakApart``): one only its source run holds, a column-break
|
|
437
|
+
block's, or the page break that opens the paragraph."""
|
|
438
|
+
if not self._is_collapsed_range or not self._holds_break() or tracking(self._session):
|
|
439
|
+
return None
|
|
440
|
+
if self._inline_snapshot.get("breakApart") is True:
|
|
441
|
+
return None
|
|
442
|
+
if self._inline_snapshot.get("break") == "column" and not server_takes(self._session, "inlineColumnBreak"):
|
|
443
|
+
return None
|
|
444
|
+
return self._later_runs()
|
|
445
|
+
|
|
410
446
|
def _add_run_ref(self, command: dict) -> dict:
|
|
411
447
|
"""Add the run identity of an insert at the end of this run.
|
|
412
448
|
|
|
@@ -415,7 +451,7 @@ class Run:
|
|
|
415
451
|
"""
|
|
416
452
|
ref = run_ref(self)
|
|
417
453
|
if ref is not None:
|
|
418
|
-
command["run"] = ref
|
|
454
|
+
command["run"] = {**(command.get("run") or {}), **ref}
|
|
419
455
|
return command
|
|
420
456
|
|
|
421
457
|
def _note_length_change(
|
|
@@ -580,9 +616,28 @@ class Run:
|
|
|
580
616
|
set, so we ``getattr`` it.
|
|
581
617
|
"""
|
|
582
618
|
pending = getattr(self, "_pending_inline", None)
|
|
583
|
-
if not pending
|
|
619
|
+
if not pending:
|
|
620
|
+
return
|
|
621
|
+
# An empty run that holds a page or column break: docx-studio formats
|
|
622
|
+
# the break's run, which it tells by the run's identity.
|
|
623
|
+
identity = self._break_run_identity()
|
|
624
|
+
if self._is_collapsed_range and identity is None:
|
|
584
625
|
return
|
|
585
626
|
self._pending_inline = {}
|
|
627
|
+
if identity is not None:
|
|
628
|
+
run_sync(
|
|
629
|
+
self._session.doc.format.apply(
|
|
630
|
+
{
|
|
631
|
+
"target": self._text_range,
|
|
632
|
+
"inline": pending,
|
|
633
|
+
"wholeRun": True,
|
|
634
|
+
"run": {"laterRuns": identity},
|
|
635
|
+
},
|
|
636
|
+
),
|
|
637
|
+
)
|
|
638
|
+
# Its break holds the formatting now, which what it takes next continues.
|
|
639
|
+
self._fresh = False
|
|
640
|
+
return
|
|
586
641
|
# An emptied run's kept formatting turns off each toggle it did not
|
|
587
642
|
# read (``_formatting_from_snapshot``), only so that its next text takes
|
|
588
643
|
# none from the paragraph or the run before it. Those are no
|
|
@@ -669,7 +724,9 @@ class Run:
|
|
|
669
724
|
)
|
|
670
725
|
|
|
671
726
|
drawing = self._inline_snapshot.get("drawing")
|
|
672
|
-
|
|
727
|
+
# A legacy VML picture or an OLE object (``w:pict``, ``w:object``) is no
|
|
728
|
+
# ``w:drawing``: python-docx yields nothing for it.
|
|
729
|
+
if isinstance(drawing, dict) and drawing.get("legacy") is not True:
|
|
673
730
|
from docx.drawing import Drawing
|
|
674
731
|
|
|
675
732
|
# The picture is at the run's start: text added to the run follows it.
|
|
@@ -682,6 +739,11 @@ class Run:
|
|
|
682
739
|
if "\f" not in text:
|
|
683
740
|
if _word_text(text, font):
|
|
684
741
|
yield _word_text(text, font)
|
|
742
|
+
elif self._inline_snapshot.get("break") in ("page", "column"):
|
|
743
|
+
# python-docx reads a page or column break as text, an empty
|
|
744
|
+
# string: a run holding one and no other text yields "". An
|
|
745
|
+
# empty run (a comment reference's) yields nothing.
|
|
746
|
+
yield ""
|
|
685
747
|
return
|
|
686
748
|
# Split on hard page-break sentinel; yield text segments and
|
|
687
749
|
# RenderedPageBreak proxies between them. The proxy carries the
|
|
@@ -752,6 +814,16 @@ class Run:
|
|
|
752
814
|
self._flush_pending_inline()
|
|
753
815
|
return
|
|
754
816
|
if self._is_collapsed_range:
|
|
817
|
+
# python-docx replaces all of the run's content, its page or
|
|
818
|
+
# column break too: an empty run holding one has it removed first.
|
|
819
|
+
if self._holds_break() and self._replaces_breaks():
|
|
820
|
+
clear: dict = {"target": self._text_range, "text": "", "wholeRun": True}
|
|
821
|
+
# Which of the runs at its place this one is, where more than one holds a break.
|
|
822
|
+
later = self._later_runs()
|
|
823
|
+
if later is not None:
|
|
824
|
+
clear["run"] = {"laterRuns": later}
|
|
825
|
+
run_sync(self._session.doc.replace(clear))
|
|
826
|
+
self._forget_break()
|
|
755
827
|
# An empty run has nothing to replace: the text is appended to
|
|
756
828
|
# it, with the formatting rule of ``add_text``.
|
|
757
829
|
if value and tracking(self._session) and any(ch in "\t\r\n" for ch in value):
|
|
@@ -814,6 +886,9 @@ class Run:
|
|
|
814
886
|
# write replaces the run's ``w:footnoteReference`` too (``""`` included),
|
|
815
887
|
# and the export then leaves out the note nothing references.
|
|
816
888
|
getattr(self, "_inline_snapshot", {}).pop("noteReference", None)
|
|
889
|
+
# The run's page and column breaks went with its text.
|
|
890
|
+
if self._holds_break() and not tracked and self._replaces_breaks():
|
|
891
|
+
self._forget_break()
|
|
817
892
|
if tracked:
|
|
818
893
|
self._note_tracked_replacement(old_range, value)
|
|
819
894
|
else:
|
|
@@ -929,6 +1004,41 @@ class Run:
|
|
|
929
1004
|
# any pending inline formatting now that there's text to mark.
|
|
930
1005
|
self._flush_pending_inline()
|
|
931
1006
|
|
|
1007
|
+
def _holds_break(self) -> bool:
|
|
1008
|
+
"""Whether this run holds a page or column break (``break``, as
|
|
1009
|
+
docx-studio's read of it or :meth:`add_break` noted it)."""
|
|
1010
|
+
snapshot: object = getattr(self, "_inline_snapshot", None)
|
|
1011
|
+
return isinstance(snapshot, dict) and snapshot.get("break") in ("page", "column")
|
|
1012
|
+
|
|
1013
|
+
def _replaces_breaks(self) -> bool:
|
|
1014
|
+
"""Whether a ``wholeRun`` Replace of this run replaces its page and
|
|
1015
|
+
column breaks too, as python-docx's ``run.text = …`` and
|
|
1016
|
+
``run.clear()`` do: on a docx-studio that reports
|
|
1017
|
+
``capabilities.wholeRunBreaks``, without tracked changes (a tracked
|
|
1018
|
+
replacement keeps the breaks). An older one keeps a break at the run's
|
|
1019
|
+
edge, and the proxy keeps it too."""
|
|
1020
|
+
return not tracking(self._session) and server_takes(self._session, "wholeRunBreaks")
|
|
1021
|
+
|
|
1022
|
+
def _forget_break(self) -> None:
|
|
1023
|
+
"""The run holds no page or column break now: its ``break`` goes, and
|
|
1024
|
+
whether the paragraph held it (``breakApart``) with it."""
|
|
1025
|
+
self._inline_snapshot.pop("break", None)
|
|
1026
|
+
self._inline_snapshot.pop("breakApart", None)
|
|
1027
|
+
|
|
1028
|
+
def _note_break(self, kind: str, *, held: bool) -> None:
|
|
1029
|
+
"""Record that this run holds a page or column break (``kind``), as
|
|
1030
|
+
docx-studio's read of it says (``break``), so that
|
|
1031
|
+
:meth:`iter_inner_content` yields python-docx's ``""`` for it while it
|
|
1032
|
+
has no text. A break the paragraph holds (``held``: one ``add_break``
|
|
1033
|
+
put in the run, inline) is one a format of the run reaches, with the
|
|
1034
|
+
break apart from the paragraph it may hold too, as docx-studio then
|
|
1035
|
+
reads the run: no longer ``breakApart``."""
|
|
1036
|
+
snapshot: object = getattr(self, "_inline_snapshot", None)
|
|
1037
|
+
if isinstance(snapshot, dict):
|
|
1038
|
+
snapshot.setdefault("break", kind)
|
|
1039
|
+
if held:
|
|
1040
|
+
snapshot.pop("breakApart", None)
|
|
1041
|
+
|
|
932
1042
|
def add_break(self, break_type: "WD_BREAK" = WD_BREAK.LINE) -> None:
|
|
933
1043
|
"""Insert a break at the end of the run.
|
|
934
1044
|
|
|
@@ -949,11 +1059,13 @@ class Run:
|
|
|
949
1059
|
matching ``breakType``
|
|
950
1060
|
- ``LINE`` → ``doc.insertLineBreak`` (a real Word line-break node)
|
|
951
1061
|
- ``COLUMN`` → ``doc.insertLineBreak`` with ``breakType: "column"``:
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1062
|
+
the ``<w:br w:type="column"/>`` at the end of the run, in it, as
|
|
1063
|
+
python-docx writes it, when the server reports
|
|
1064
|
+
``capabilities.inlineColumnBreak`` in ``Info``. It takes no room in
|
|
1065
|
+
the paragraph's text-address space, and a run holding nothing else
|
|
1066
|
+
yields ``""``, as python-docx's does. An older server writes it
|
|
1067
|
+
after the paragraph's content, as a run of its own; one before
|
|
1068
|
+
column breaks inserts a line break instead.
|
|
957
1069
|
- ``LINE_CLEAR_LEFT`` / ``LINE_CLEAR_RIGHT`` / ``LINE_CLEAR_ALL``
|
|
958
1070
|
(``TEXT_WRAPPING`` is python-docx's alias of ``LINE_CLEAR_ALL``) —
|
|
959
1071
|
DOCX Studio has no dedicated wire op for these, so they degrade to
|
|
@@ -1002,6 +1114,9 @@ class Run:
|
|
|
1002
1114
|
if self._continues_own_formatting():
|
|
1003
1115
|
page_break["inheritMarks"] = True
|
|
1004
1116
|
run_sync(self._session.doc.insert_line_break(page_break))
|
|
1117
|
+
self._note_break("page", held=True)
|
|
1118
|
+
# Formatting set on the empty run before its break: the break's run takes it.
|
|
1119
|
+
self._flush_pending_inline()
|
|
1005
1120
|
return
|
|
1006
1121
|
|
|
1007
1122
|
if bt is WD_BREAK.PAGE:
|
|
@@ -1040,9 +1155,17 @@ class Run:
|
|
|
1040
1155
|
return
|
|
1041
1156
|
|
|
1042
1157
|
if bt is WD_BREAK.COLUMN:
|
|
1043
|
-
column_break =
|
|
1044
|
-
|
|
1045
|
-
|
|
1158
|
+
column_break: dict = {"blockId": self._block_id, "offset": end, "breakType": "column"}
|
|
1159
|
+
if server_takes(self._session, "inlineColumnBreak"):
|
|
1160
|
+
# At the end of this run, in it, as python-docx writes it.
|
|
1161
|
+
column_break["inline"] = True
|
|
1162
|
+
self._mark_append(column_break)
|
|
1163
|
+
if self._continues_own_formatting():
|
|
1164
|
+
column_break["inheritMarks"] = True
|
|
1165
|
+
run_sync(self._session.doc.insert_line_break(self._add_run_ref(column_break)))
|
|
1166
|
+
self._note_break("column", held=column_break.get("inline") is True)
|
|
1167
|
+
# Formatting set on the empty run before its break: the break's run takes it.
|
|
1168
|
+
self._flush_pending_inline()
|
|
1046
1169
|
return
|
|
1047
1170
|
|
|
1048
1171
|
if bt in degraded_to_line:
|
|
@@ -1603,6 +1726,23 @@ class Run:
|
|
|
1603
1726
|
)
|
|
1604
1727
|
return
|
|
1605
1728
|
self._note_inline_applied(kwargs)
|
|
1729
|
+
identity = self._break_run_identity()
|
|
1730
|
+
if identity is not None:
|
|
1731
|
+
# The run holds only a page or column break: python-docx formats its
|
|
1732
|
+
# ``w:r``, and docx-studio its break, which it tells by the run's identity.
|
|
1733
|
+
run_sync(
|
|
1734
|
+
self._session.doc.format.apply(
|
|
1735
|
+
{
|
|
1736
|
+
"target": self._text_range,
|
|
1737
|
+
"inline": kwargs,
|
|
1738
|
+
"wholeRun": True,
|
|
1739
|
+
"run": {"laterRuns": identity},
|
|
1740
|
+
},
|
|
1741
|
+
),
|
|
1742
|
+
)
|
|
1743
|
+
# Its break holds the formatting now, which what it takes next continues.
|
|
1744
|
+
self._fresh = False
|
|
1745
|
+
return
|
|
1606
1746
|
if self._is_collapsed_range:
|
|
1607
1747
|
pending = getattr(self, "_pending_inline", None)
|
|
1608
1748
|
if pending is 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.32.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"
|
|
@@ -299,7 +299,7 @@ CASES: list[ComplexCase] = [
|
|
|
299
299
|
"from docx.enum.table import WD_TABLE_ALIGNMENT, WD_TABLE_DIRECTION\n"
|
|
300
300
|
"t = doc.add_table(rows=2, cols=2)\n"
|
|
301
301
|
"t.alignment = WD_TABLE_ALIGNMENT.CENTER\n"
|
|
302
|
-
"t.
|
|
302
|
+
"t.table_direction = WD_TABLE_DIRECTION.LTR\n"
|
|
303
303
|
"t.autofit = True"
|
|
304
304
|
),
|
|
305
305
|
expected_ops=("tables.setTableOptions", "tables.setLayout"),
|
|
@@ -248,6 +248,8 @@ class FakeDocState:
|
|
|
248
248
|
info["latentStyles"] = self.latent_styles
|
|
249
249
|
if (params or {}).get("includeCoreProperties") and self.core_properties is not None:
|
|
250
250
|
info["coreProperties"] = dict(self.core_properties)
|
|
251
|
+
# `tables.setLayout` below writes `tableDirection`, as a docx-studio reporting it does.
|
|
252
|
+
info["capabilities"] = {"tableDirection": True}
|
|
251
253
|
return info
|
|
252
254
|
return {"ok": True}
|
|
253
255
|
|