athena-python-docx 0.37.0__tar.gz → 0.38.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.37.0 → athena_python_docx-0.38.0}/PKG-INFO +1 -1
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/commands.py +6 -2
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/table.py +7 -1
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/run.py +101 -21
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/pyproject.toml +1 -1
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_drawing_image.py +56 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_enum_parity.py +14 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_ruby_reads_python_docx_parity.py +18 -2
- athena_python_docx-0.38.0/tests/test_run_break_inner_content.py +254 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_later_runs.py +59 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_mark_inheritance.py +35 -40
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_add_row_grid_row.py +29 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/uv.lock +1 -1
- athena_python_docx-0.37.0/tests/test_run_break_inner_content.py +0 -121
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/.gitignore +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/AGENTS.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/CLAUDE.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/README.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_capabilities.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_citations.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_http.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_postproc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_proxy.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_references.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_run_order.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_tracked.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/_xml_text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/api.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/blkcntnr.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/charts.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/client.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/comments.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/document.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/drawing/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/base.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/dml.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/errors.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/fields.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/image/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/image/exceptions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/image/image.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/math.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/section.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/session.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/settings.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/shape.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/shared.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/styles/_table.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/styles/latent.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/paragraph.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/toc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/docx/typing.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/agent_documents.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/picture_runs.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/return_types.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fixtures/field_reads.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fixtures/note_reference_reads.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fixtures/ruby_reads.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/fixtures/symbol_reads.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/baseline.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/fixture_scripts.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/reader.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/runner.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/sdk_driver.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/stock_driver.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/live/test_live_runner.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_add_section.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_alignment_values.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_athena_extension_creates_session_open.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_batch_chunking.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_battery_cases.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_borders_spec.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_fastpath_runs.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_inner_run_guard.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_merge.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_nested_tables.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_paragraphs_listed.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_citations.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_color_format_theme.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_comment_paragraphs.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_comments_first_read.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_content_control_value.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_core_properties.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_document_settings_session_open.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_empty_hyperlinks.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_export_docx_clean.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_export_rescue_anchors.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_field_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_field_refresh.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_field_runs.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_flushed_write_failures.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_inline_page_break.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_alt_text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_size.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_inline_shape_type.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_inline_shapes_floating.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_latent_style_writes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_line_clear_break.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_merged_cell_identity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_missing_modules.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_nested_table_refused.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_page_break.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_paragraph_delete.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_paragraph_indent_reads.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_paragraph_text_empty_run.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_parfmt_clears.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_pdf_export_and_page_renders.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_postproc_ref_restore.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_proxy_equality.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_read_run_ranges.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_rendered_page_breaks.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_repeated_node_read.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_restart_numbering.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_round_trip_smoke_script.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_add_picture_anchor.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_edges.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_formatting_wire.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_identity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_page_number_blocks.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_table_style_objects.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_text_python_docx.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_run_unmodeled_toggles.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_sdk_reads_served.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_section_read_lengths.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_delete.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_formatting_writes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_metadata_writes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_names.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_tab_stops.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_style_tab_stops_read.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_tab_stop_writes.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_anchors.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_clears.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_direction.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_read_reuse.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_text_control_characters.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_tracked_revisions_offsets.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_unmapped_alignment_reads.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_uv_lock_version.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_xml_incompatible_text.py +0 -0
- {athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.38.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>
|
|
@@ -568,14 +568,18 @@ class TablesInsertRow(Command):
|
|
|
568
568
|
"""``grid_row`` is python-docx's ``Table.add_row()``: the row goes after
|
|
569
569
|
the table's last one, with a cell for each grid column as wide as the
|
|
570
570
|
column, holding one empty paragraph, and nothing of the rows above.
|
|
571
|
-
|
|
572
|
-
|
|
571
|
+
``copy_format_from`` is the Athena extension
|
|
572
|
+
``Table.add_row(copy_format_from=k)``: the row goes after the table's
|
|
573
|
+
last one, formatted as Word's Insert Row below row ``k`` formats it.
|
|
574
|
+
Without either, the row is Word's Insert Row next to ``row_index``. A
|
|
575
|
+
docx-studio that predates a field ignores it."""
|
|
573
576
|
|
|
574
577
|
node_id: str
|
|
575
578
|
row_index: int
|
|
576
579
|
position: str # "above" | "below"
|
|
577
580
|
count: int = 1
|
|
578
581
|
grid_row: bool | None = None
|
|
582
|
+
copy_format_from: int | None = None
|
|
579
583
|
|
|
580
584
|
|
|
581
585
|
@dataclass
|
|
@@ -1240,7 +1240,13 @@ class Table:
|
|
|
1240
1240
|
self._session.doc.tables.get_properties({"nodeId": self._fresh_node_id()}),
|
|
1241
1241
|
)
|
|
1242
1242
|
if isinstance(info, dict):
|
|
1243
|
-
|
|
1243
|
+
raw: object = info.get("alignment")
|
|
1244
|
+
member = WD_PARAGRAPH_ALIGNMENT.from_docx_studio(raw)
|
|
1245
|
+
# python-docx reads `w:jc` through `from_xml`, which raises
|
|
1246
|
+
# ValueError for a value it has no member for (`start`, `end`).
|
|
1247
|
+
if member is None and isinstance(raw, str) and raw:
|
|
1248
|
+
return WD_PARAGRAPH_ALIGNMENT.from_xml(raw)
|
|
1249
|
+
return member
|
|
1244
1250
|
return None
|
|
1245
1251
|
|
|
1246
1252
|
@alignment.setter
|
|
@@ -454,11 +454,16 @@ class Run:
|
|
|
454
454
|
formatting, so the formatting waits for content the run takes. So
|
|
455
455
|
does a break the read says is no node of the paragraph
|
|
456
456
|
(``breakApart``): one only its source run holds, a column-break
|
|
457
|
-
block's, or the page break that opens the paragraph.
|
|
457
|
+
block's, or the page break that opens the paragraph. The paragraph's
|
|
458
|
+
closing page break run (``closingBreak``) is formatted where the
|
|
459
|
+
docx-studio reports ``capabilities.closingBreakRunFormat``, which puts
|
|
460
|
+
its breaks back in the paragraph to take it."""
|
|
458
461
|
if not self._is_collapsed_range or not self._holds_break() or tracking(self._session):
|
|
459
462
|
return None
|
|
460
463
|
if self._inline_snapshot.get("breakApart") is True:
|
|
461
|
-
|
|
464
|
+
closing = self._inline_snapshot.get("closingBreak") is True
|
|
465
|
+
if not closing or not server_takes(self._session, "closingBreakRunFormat"):
|
|
466
|
+
return None
|
|
462
467
|
if self._inline_snapshot.get("break") == "column" and not server_takes(self._session, "inlineColumnBreak"):
|
|
463
468
|
return None
|
|
464
469
|
return self._later_runs()
|
|
@@ -468,14 +473,23 @@ class Run:
|
|
|
468
473
|
and no text (a picture's run, ``drawing``), which a whole-run
|
|
469
474
|
``FormatApply`` of its collapsed range formats, untracked, on a
|
|
470
475
|
docx-studio that reports ``capabilities.pictureRuns``: python-docx
|
|
471
|
-
formats the run's ``w:r``, and docx-studio its picture.
|
|
476
|
+
formats the run's ``w:r``, and docx-studio its picture. A legacy
|
|
477
|
+
picture's or object's run (``w:pict``, ``w:object``: ``drawing.legacy``
|
|
478
|
+
with its ``imageId``) too, on one that reports
|
|
479
|
+
``capabilities.legacyPictureRuns``; not a preserved shape's (a
|
|
480
|
+
``drawing.legacy`` with no ``imageId``), which no picture holds and the
|
|
481
|
+
format cannot reach. Else None."""
|
|
472
482
|
if not self._is_collapsed_range or tracking(self._session):
|
|
473
483
|
return None
|
|
474
484
|
drawing = self._inline_snapshot.get("drawing")
|
|
475
|
-
if not isinstance(drawing, dict)
|
|
485
|
+
if not isinstance(drawing, dict):
|
|
476
486
|
return None
|
|
477
487
|
if not server_takes(self._session, "pictureRuns"):
|
|
478
488
|
return None
|
|
489
|
+
if drawing.get("legacy") is True and (
|
|
490
|
+
not drawing.get("imageId") or not server_takes(self._session, "legacyPictureRuns")
|
|
491
|
+
):
|
|
492
|
+
return None
|
|
479
493
|
return self._later_runs()
|
|
480
494
|
|
|
481
495
|
def _empty_run_identity(self) -> int | None:
|
|
@@ -866,6 +880,15 @@ class Run:
|
|
|
866
880
|
items: list[tuple[int, float, dict, bool]] = [
|
|
867
881
|
(offset, index, info, True) for index, (offset, info) in enumerate(pictures)
|
|
868
882
|
]
|
|
883
|
+
# python-docx yields "" for each stretch of the run that the pictures
|
|
884
|
+
# bound and that holds a page or column break and no text, by how
|
|
885
|
+
# many pictures come before it (``emptyTextAfterPictures``). From a
|
|
886
|
+
# docx-studio that does not say, a run of a break and pictures and
|
|
887
|
+
# no text yields the break's "" before them.
|
|
888
|
+
empty_after = self._empty_text_after_pictures()
|
|
889
|
+
if empty_after is None:
|
|
890
|
+
breaks = not raw and self._inline_snapshot.get("break") in ("page", "column")
|
|
891
|
+
empty_after = {0} if breaks else set()
|
|
869
892
|
rendered = self._rendered_page_breaks()
|
|
870
893
|
for info in rendered:
|
|
871
894
|
offset = int(info.get("offset", 0) or 0)
|
|
@@ -875,15 +898,23 @@ class Run:
|
|
|
875
898
|
items.append((offset, after - 0.5, info, False))
|
|
876
899
|
items.sort(key=lambda item: (item[0], item[1]))
|
|
877
900
|
cut = 0
|
|
901
|
+
pictures_yielded = 0
|
|
878
902
|
for offset, _order, info, is_picture in items:
|
|
879
903
|
at = min(max(offset, cut), len(raw))
|
|
880
904
|
if _word_text(raw[cut:at], font):
|
|
881
905
|
yield _word_text(raw[cut:at], font)
|
|
882
906
|
if not is_picture:
|
|
883
907
|
yield RenderedPageBreak(paragraph=self._page_break_paragraph(), offset=self._range[0] + at, info=info)
|
|
884
|
-
|
|
885
|
-
|
|
908
|
+
else:
|
|
909
|
+
if pictures_yielded in empty_after:
|
|
910
|
+
yield ""
|
|
911
|
+
empty_after.discard(pictures_yielded)
|
|
912
|
+
if info.get("legacy") is not True:
|
|
913
|
+
yield Drawing(session=self._session, info=info)
|
|
914
|
+
pictures_yielded += 1
|
|
886
915
|
cut = at
|
|
916
|
+
if pictures_yielded in empty_after:
|
|
917
|
+
yield ""
|
|
887
918
|
if _word_text(raw[cut:], font):
|
|
888
919
|
yield _word_text(raw[cut:], font)
|
|
889
920
|
return
|
|
@@ -1240,6 +1271,34 @@ class Run:
|
|
|
1240
1271
|
snapshot.setdefault("break", kind)
|
|
1241
1272
|
if held:
|
|
1242
1273
|
snapshot.pop("breakApart", None)
|
|
1274
|
+
self._note_empty_text_after_pictures()
|
|
1275
|
+
|
|
1276
|
+
def _note_empty_text_after_pictures(self) -> None:
|
|
1277
|
+
"""This run took a page or column break at its end, after its pictures:
|
|
1278
|
+
python-docx yields its ``""`` after the last of them while no text
|
|
1279
|
+
follows it there (``emptyTextAfterPictures``). A picture's run
|
|
1280
|
+
(``drawing``) holds its picture among its pictures (``pictures``) then."""
|
|
1281
|
+
snapshot = self._inline_snapshot
|
|
1282
|
+
alone = snapshot.get("drawing")
|
|
1283
|
+
pictures = self._pictures() or ([(0, alone)] if isinstance(alone, dict) else [])
|
|
1284
|
+
if not pictures or self._raw_text()[pictures[-1][0]:]:
|
|
1285
|
+
return
|
|
1286
|
+
if isinstance(alone, dict):
|
|
1287
|
+
snapshot.pop("drawing")
|
|
1288
|
+
snapshot["pictures"] = [{"offset": 0, "drawing": alone}]
|
|
1289
|
+
places = snapshot.setdefault("emptyTextAfterPictures", [])
|
|
1290
|
+
if isinstance(places, list) and len(pictures) not in places:
|
|
1291
|
+
places.append(len(pictures))
|
|
1292
|
+
|
|
1293
|
+
def _empty_text_after_pictures(self) -> "set[int] | None":
|
|
1294
|
+
"""Where :meth:`iter_inner_content` yields ``""`` among this run's
|
|
1295
|
+
pictures (``emptyTextAfterPictures``): each stretch the pictures bound
|
|
1296
|
+
that holds a page or column break and no text, by how many pictures
|
|
1297
|
+
come before it. None when the read does not say."""
|
|
1298
|
+
places: object = self._inline_snapshot.get("emptyTextAfterPictures")
|
|
1299
|
+
if not isinstance(places, list):
|
|
1300
|
+
return None
|
|
1301
|
+
return {p for p in places if isinstance(p, int) and not isinstance(p, bool)}
|
|
1243
1302
|
|
|
1244
1303
|
def add_break(self, break_type: "WD_BREAK" = WD_BREAK.LINE) -> None:
|
|
1245
1304
|
"""Insert a break at the end of the run.
|
|
@@ -1521,17 +1580,25 @@ class Run:
|
|
|
1521
1580
|
def _hold_picture(self, drawing: dict) -> None:
|
|
1522
1581
|
"""This run took the picture ``drawing`` at its end (``run.add_picture``),
|
|
1523
1582
|
as the next read gives it: a run of a picture alone as a picture's run
|
|
1524
|
-
(``drawing``), else among its pictures (``pictures``) where its text ends.
|
|
1583
|
+
(``drawing``), else among its pictures (``pictures``) where its text ends.
|
|
1584
|
+
A run of a page or column break and no text holds it among its
|
|
1585
|
+
pictures, after the break's ``""`` (``emptyTextAfterPictures``)."""
|
|
1525
1586
|
snapshot = self._inline_snapshot
|
|
1526
1587
|
held = self._pictures()
|
|
1527
1588
|
alone = snapshot.get("drawing")
|
|
1528
|
-
|
|
1589
|
+
raw = self._raw_text()
|
|
1590
|
+
break_first = not held and not raw and not isinstance(alone, dict) and snapshot.get("break") in ("page", "column")
|
|
1591
|
+
if not held and not raw and not isinstance(alone, dict) and not break_first:
|
|
1529
1592
|
snapshot["drawing"] = drawing
|
|
1530
1593
|
return
|
|
1531
1594
|
if isinstance(alone, dict):
|
|
1532
1595
|
held = [(0, snapshot.pop("drawing"))]
|
|
1533
|
-
held.append((len(
|
|
1596
|
+
held.append((len(raw), drawing))
|
|
1534
1597
|
snapshot["pictures"] = [{"offset": offset, "drawing": info} for offset, info in held]
|
|
1598
|
+
if break_first:
|
|
1599
|
+
places = snapshot.setdefault("emptyTextAfterPictures", [])
|
|
1600
|
+
if isinstance(places, list) and 0 not in places:
|
|
1601
|
+
places.append(0)
|
|
1535
1602
|
|
|
1536
1603
|
@athena_extension(
|
|
1537
1604
|
issue=498,
|
|
@@ -1882,15 +1949,19 @@ class Run:
|
|
|
1882
1949
|
|
|
1883
1950
|
# ---- formatting helpers ----
|
|
1884
1951
|
def _formatting_from_snapshot(self) -> dict:
|
|
1885
|
-
"""This run's formatting as a ``format.apply`` inline bag
|
|
1952
|
+
"""This run's own formatting as a ``format.apply`` inline bag: the
|
|
1953
|
+
values the run sets itself, an explicit off toggle (``w:b w:val="0"``)
|
|
1954
|
+
included, as python-docx keeps the run's ``w:rPr`` for its next text.
|
|
1886
1955
|
|
|
1887
1956
|
Only for a snapshot with every formatting key that is set
|
|
1888
|
-
(``_marks_known``)
|
|
1889
|
-
|
|
1890
|
-
|
|
1957
|
+
(``_marks_known``). A toggle the run does not set stays unset: the new
|
|
1958
|
+
text, which docx-studio gives no formatting of its own (no
|
|
1959
|
+
``inheritMarks``), shows what the styles give it, as python-docx's
|
|
1960
|
+
does. Sending it as ``False`` wrote an explicit off, so text written
|
|
1961
|
+
into an emptied heading run lost the heading's bold.
|
|
1891
1962
|
"""
|
|
1892
1963
|
snapshot = self._inline_snapshot
|
|
1893
|
-
out: dict = {
|
|
1964
|
+
out: dict = {}
|
|
1894
1965
|
for key in _RUN_MARK_KEYS:
|
|
1895
1966
|
value = snapshot.get(key)
|
|
1896
1967
|
if value is not None:
|
|
@@ -2005,6 +2076,9 @@ class Run:
|
|
|
2005
2076
|
)
|
|
2006
2077
|
# Its break or picture holds the formatting now, which what it takes next continues.
|
|
2007
2078
|
self._fresh = False
|
|
2079
|
+
# A closing page break run's breaks are the paragraph's now, as the next read gives them.
|
|
2080
|
+
if self._inline_snapshot.pop("closingBreak", None) is True:
|
|
2081
|
+
self._inline_snapshot.pop("breakApart", None)
|
|
2008
2082
|
return
|
|
2009
2083
|
if self._is_collapsed_range:
|
|
2010
2084
|
pending = getattr(self, "_pending_inline", None)
|
|
@@ -2019,17 +2093,23 @@ class Run:
|
|
|
2019
2093
|
{"target": self._text_range, "inline": kwargs, "wholeRun": True},
|
|
2020
2094
|
),
|
|
2021
2095
|
)
|
|
2022
|
-
self._edited_ruby()
|
|
2096
|
+
self._edited_ruby(formatted=True)
|
|
2023
2097
|
|
|
2024
|
-
def _edited_ruby(self) -> None:
|
|
2098
|
+
def _edited_ruby(self, *, formatted: bool = False) -> None:
|
|
2025
2099
|
"""This run's text or formatting changed: docx-studio writes the base
|
|
2026
2100
|
text of each ruby it held as text from then on (it keeps no guide
|
|
2027
|
-
through an edit), so the run reads it as text.
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2101
|
+
through an edit), so the run reads it as text. A docx-studio that
|
|
2102
|
+
reports ``capabilities.rubyThroughFormat`` keeps the ruby through a
|
|
2103
|
+
whole-run format (``formatted``), as python-docx keeps the run's
|
|
2104
|
+
``w:ruby``, so the run goes on reading it as the ruby's. It writes the
|
|
2105
|
+
run's symbol-block characters as a ``w:sym`` in the font the run owns
|
|
2106
|
+
too, so a read's null ``symbolFont`` (a source ``w:t``'s characters)
|
|
2107
|
+
gives way to the run's font (``_symbol_font``)."""
|
|
2031
2108
|
snapshot = getattr(self, "_inline_snapshot", {})
|
|
2032
|
-
|
|
2109
|
+
if "ruby" in snapshot and not (
|
|
2110
|
+
formatted and server_takes(getattr(self, "_session", None), "rubyThroughFormat")
|
|
2111
|
+
):
|
|
2112
|
+
snapshot.pop("ruby", None)
|
|
2033
2113
|
if "symbolFont" in snapshot and snapshot["symbolFont"] is None:
|
|
2034
2114
|
snapshot.pop("symbolFont")
|
|
2035
2115
|
|
|
@@ -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.38.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"
|
|
@@ -466,6 +466,62 @@ class TestRunsHoldingPictures:
|
|
|
466
466
|
assert formats == []
|
|
467
467
|
assert picture_run._pending_inline == {"italic": True}
|
|
468
468
|
|
|
469
|
+
@pytest.mark.parametrize(("capability", "sent"), [(True, True), (False, False)])
|
|
470
|
+
def test_formatting_a_legacy_objects_run_formats_it_where_docx_studio_formats_them(
|
|
471
|
+
self, mock_session: Any, fake_sd_methods: Any, capability: bool, sent: bool
|
|
472
|
+
) -> None:
|
|
473
|
+
"""``p.runs[1].italic = True`` of an embedded object's run
|
|
474
|
+
(``<w:r><w:object>…</w:object></w:r>``, read as ``drawing.legacy``):
|
|
475
|
+
python-docx formats its ``w:r``. A docx-studio without
|
|
476
|
+
``capabilities.legacyPictureRuns`` keeps the formatting for the text the
|
|
477
|
+
run takes, as before."""
|
|
478
|
+
fake_sd_methods.scripted_returns["info"] = {
|
|
479
|
+
"capabilities": {"pictureRuns": True, "legacyPictureRuns": capability, "runIdentity": True}
|
|
480
|
+
}
|
|
481
|
+
paragraph = _paragraph(
|
|
482
|
+
mock_session,
|
|
483
|
+
fake_sd_methods,
|
|
484
|
+
[{"run": {"text": "The figures "}}, {"drawing": {"imageId": "p1:0:aa", "legacy": True}}, {"run": {"text": " sit here."}}],
|
|
485
|
+
)
|
|
486
|
+
object_run = paragraph.runs[1]
|
|
487
|
+
|
|
488
|
+
object_run.italic = True
|
|
489
|
+
|
|
490
|
+
formats = [params for op, params in fake_sd_methods.calls if op == "format.apply"]
|
|
491
|
+
if sent:
|
|
492
|
+
assert formats == [
|
|
493
|
+
{
|
|
494
|
+
"target": {"kind": "text", "blockId": "p1", "range": {"start": 12, "end": 12}},
|
|
495
|
+
"inline": {"italic": True},
|
|
496
|
+
"wholeRun": True,
|
|
497
|
+
"run": {"laterRuns": 0},
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
|
+
else:
|
|
501
|
+
assert formats == []
|
|
502
|
+
assert object_run._pending_inline == {"italic": True}
|
|
503
|
+
|
|
504
|
+
def test_formatting_a_preserved_shapes_run_stays_pending(self, mock_session: Any, fake_sd_methods: Any) -> None:
|
|
505
|
+
"""A shape docx-studio keeps as it was (``mc:AlternateContent``) reads
|
|
506
|
+
as ``drawing.legacy`` with no ``imageId``: no picture holds it, so a
|
|
507
|
+
format of its run would reply ``formatted: false``. Its formatting stays
|
|
508
|
+
pending, as before, also on a docx-studio that reports
|
|
509
|
+
``legacyPictureRuns``."""
|
|
510
|
+
fake_sd_methods.scripted_returns["info"] = {
|
|
511
|
+
"capabilities": {"pictureRuns": True, "legacyPictureRuns": True, "runIdentity": True}
|
|
512
|
+
}
|
|
513
|
+
paragraph = _paragraph(
|
|
514
|
+
mock_session,
|
|
515
|
+
fake_sd_methods,
|
|
516
|
+
[{"run": {"text": "Before "}}, {"drawing": {"imageId": None, "legacy": True}}, {"run": {"text": " after"}}],
|
|
517
|
+
)
|
|
518
|
+
shape_run = paragraph.runs[1]
|
|
519
|
+
|
|
520
|
+
shape_run.italic = True
|
|
521
|
+
|
|
522
|
+
assert [params for op, params in fake_sd_methods.calls if op == "format.apply"] == []
|
|
523
|
+
assert shape_run._pending_inline == {"italic": True}
|
|
524
|
+
|
|
469
525
|
def test_a_pictures_run_reads_its_formatting(self, mock_session: Any, fake_sd_methods: Any) -> None:
|
|
470
526
|
"""python-docx reads a picture's run's ``w:rPr``: docx-studio reads its
|
|
471
527
|
formatting on the picture's inline beside its drawing."""
|
|
@@ -386,6 +386,20 @@ def test_getters_return_int_members(mock_session: Any, fake_sd_methods: Any) ->
|
|
|
386
386
|
assert table.table_direction is True and table.table_direction == WD_TABLE_DIRECTION.RTL
|
|
387
387
|
|
|
388
388
|
|
|
389
|
+
@pytest.mark.parametrize("jc", ["start", "end"])
|
|
390
|
+
def test_a_table_of_start_or_end_justification_raises_as_python_docx_reads_it(
|
|
391
|
+
mock_session: Any, fake_sd_methods: Any, jc: str
|
|
392
|
+
) -> None:
|
|
393
|
+
"""python-docx 1.2.0 reads a table's ``w:jc`` through the paragraph
|
|
394
|
+
``CT_Jc``, whose enum has no member for ``start`` or ``end``."""
|
|
395
|
+
from docx.table import Table
|
|
396
|
+
|
|
397
|
+
fake_sd_methods.scripted_returns["tables.get_properties"] = {"alignment": jc}
|
|
398
|
+
table = Table(session=mock_session, node_id="tbl-1")
|
|
399
|
+
with pytest.raises(ValueError, match=f"WD_PARAGRAPH_ALIGNMENT has no XML mapping for '{jc}'"):
|
|
400
|
+
_ = table.alignment
|
|
401
|
+
|
|
402
|
+
|
|
389
403
|
@pytest.mark.parametrize(
|
|
390
404
|
"assign",
|
|
391
405
|
[
|
{athena_python_docx-0.37.0 → athena_python_docx-0.38.0}/tests/test_ruby_reads_python_docx_parity.py
RENAMED
|
@@ -13,8 +13,10 @@ is installed.
|
|
|
13
13
|
|
|
14
14
|
docx-studio keeps the base text in its run's text, the room it takes in the
|
|
15
15
|
text-address space, and gives its spans as ``ruby``: edits addressed after the
|
|
16
|
-
ruby land after it. Once the run's text
|
|
17
|
-
|
|
16
|
+
ruby land after it. Once the run's text changes, docx-studio writes the base
|
|
17
|
+
text as text, and the run reads it so; so does a format of the run, but on a
|
|
18
|
+
docx-studio that reports ``rubyThroughFormat``, which keeps the ruby through it
|
|
19
|
+
as python-docx does.
|
|
18
20
|
"""
|
|
19
21
|
|
|
20
22
|
from __future__ import annotations
|
|
@@ -190,3 +192,17 @@ def test_an_edit_of_the_rubys_run_reads_its_base_text_as_text(
|
|
|
190
192
|
|
|
191
193
|
assert _writes(fake_sd_methods)
|
|
192
194
|
assert "ruby" not in ruby._inline_snapshot
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_a_format_of_the_rubys_run_keeps_its_ruby_where_docx_studio_keeps_it(
|
|
198
|
+
mock_session: Any, fake_sd_methods: Any
|
|
199
|
+
) -> None:
|
|
200
|
+
# A docx-studio that reports `rubyThroughFormat` keeps the run's `w:ruby`
|
|
201
|
+
# through a whole-run format, as python-docx keeps it: the run still reads "".
|
|
202
|
+
fake_sd_methods.scripted_returns["info"] = {"capabilities": {"rubyThroughFormat": True}}
|
|
203
|
+
ruby = _body(mock_session, fake_sd_methods).runs[1]
|
|
204
|
+
|
|
205
|
+
ruby.bold = True
|
|
206
|
+
|
|
207
|
+
assert ruby._inline_snapshot.get("ruby") == [[0, 1]]
|
|
208
|
+
assert ruby.text == ""
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""A run holding only a page or column break, as ``Run.iter_inner_content()`` yields it.
|
|
2
|
+
|
|
3
|
+
python-docx reads a ``<w:br w:type="page"/>`` or ``<w:br w:type="column"/>`` as
|
|
4
|
+
text, an empty string, so a run holding one and no other text yields ``""``;
|
|
5
|
+
an empty ``w:r`` (a comment reference's) yields nothing. docx-studio reads such
|
|
6
|
+
a break's run as ``{"run": {"text": "", "break": "page"}}`` (or ``"column"``);
|
|
7
|
+
an older one sends no ``break`` and the run yields nothing, as before.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _make_paragraph(inlines: list[dict]) -> Any:
|
|
17
|
+
from docx.client import Session
|
|
18
|
+
from docx.text.paragraph import Paragraph
|
|
19
|
+
|
|
20
|
+
session = MagicMock(spec=Session)
|
|
21
|
+
session.asset_id = "asset_fake"
|
|
22
|
+
session.is_open = True
|
|
23
|
+
session.doc = MagicMock()
|
|
24
|
+
session.doc.get_node_by_id = AsyncMock(
|
|
25
|
+
return_value={"node": {"paragraph": {"inlines": inlines}}}
|
|
26
|
+
)
|
|
27
|
+
return Paragraph(session=session, node_id="p1", node_type="paragraph")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _inner(paragraph: Any) -> list[list[Any]]:
|
|
31
|
+
return [list(run.iter_inner_content()) for run in paragraph.runs]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_a_run_holding_only_a_page_or_column_break_yields_empty_text() -> None:
|
|
35
|
+
p = _make_paragraph(
|
|
36
|
+
[
|
|
37
|
+
{"run": {"text": "Before the breaks.", "bold": True}},
|
|
38
|
+
{"run": {"text": "", "break": "page"}},
|
|
39
|
+
{"run": {"text": "", "break": "column"}},
|
|
40
|
+
{"run": {"text": "After them.", "italic": True}},
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
assert _inner(p) == [["Before the breaks."], [""], [""], ["After them."]]
|
|
45
|
+
assert [run.text for run in p.runs] == ["Before the breaks.", "", "", "After them."]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_an_empty_run_yields_nothing() -> None:
|
|
49
|
+
# A comment reference's run, and a break's from a docx-studio that sends no ``break``.
|
|
50
|
+
p = _make_paragraph([{"run": {"text": "Commented."}}, {"run": {"text": ""}}])
|
|
51
|
+
|
|
52
|
+
assert _inner(p) == [["Commented."], []]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_the_empty_run_a_page_or_column_break_is_added_to_yields_empty_text(
|
|
56
|
+
mock_session: Any, fake_sd_methods: Any
|
|
57
|
+
) -> None:
|
|
58
|
+
from docx.enum.text import WD_BREAK
|
|
59
|
+
from docx.text.paragraph import Paragraph
|
|
60
|
+
|
|
61
|
+
fake_sd_methods.scripted_returns["info"] = {"capabilities": {"inlinePageBreak": True}}
|
|
62
|
+
paragraph = Paragraph(session=mock_session, node_id="p-1", text_len=0)
|
|
63
|
+
page = paragraph.add_run()
|
|
64
|
+
page.add_break(WD_BREAK.PAGE)
|
|
65
|
+
column = paragraph.add_run()
|
|
66
|
+
column.add_break(WD_BREAK.COLUMN)
|
|
67
|
+
empty = paragraph.add_run()
|
|
68
|
+
|
|
69
|
+
assert list(page.iter_inner_content()) == [""]
|
|
70
|
+
assert list(column.iter_inner_content()) == [""]
|
|
71
|
+
assert list(empty.iter_inner_content()) == []
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _replaces(fake: Any) -> list[dict[str, Any]]:
|
|
75
|
+
return [params for op, params in fake.calls if op == "replace"]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_clearing_a_run_holding_a_break_removes_it_and_its_proxy_forgets_it(
|
|
79
|
+
mock_session: Any, fake_sd_methods: Any
|
|
80
|
+
) -> None:
|
|
81
|
+
# python-docx: run.clear() removes all of the run's content, its w:br too.
|
|
82
|
+
from docx.enum.text import WD_BREAK
|
|
83
|
+
from docx.text.paragraph import Paragraph
|
|
84
|
+
|
|
85
|
+
fake_sd_methods.scripted_returns["info"] = {
|
|
86
|
+
"capabilities": {"inlinePageBreak": True, "wholeRunBreaks": True}
|
|
87
|
+
}
|
|
88
|
+
paragraph = Paragraph(session=mock_session, node_id="p-1", text_len=0)
|
|
89
|
+
texted = paragraph.add_run("Hello")
|
|
90
|
+
texted.add_break(WD_BREAK.PAGE)
|
|
91
|
+
alone = paragraph.add_run()
|
|
92
|
+
alone.add_break(WD_BREAK.PAGE)
|
|
93
|
+
|
|
94
|
+
texted.clear()
|
|
95
|
+
alone.clear()
|
|
96
|
+
|
|
97
|
+
assert list(texted.iter_inner_content()) == []
|
|
98
|
+
assert list(alone.iter_inner_content()) == []
|
|
99
|
+
# Each run's content went with a wholeRun Replace, the empty run's at its place.
|
|
100
|
+
assert [(r["text"], r.get("wholeRun")) for r in _replaces(fake_sd_methods)] == [
|
|
101
|
+
("", True),
|
|
102
|
+
("", True),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_a_docx_studio_that_keeps_a_run_s_breaks_keeps_them_on_the_proxy(
|
|
107
|
+
mock_session: Any, fake_sd_methods: Any
|
|
108
|
+
) -> None:
|
|
109
|
+
# Before `wholeRunBreaks`, a wholeRun Replace leaves a break at the run's edge.
|
|
110
|
+
from docx.enum.text import WD_BREAK
|
|
111
|
+
from docx.text.paragraph import Paragraph
|
|
112
|
+
|
|
113
|
+
fake_sd_methods.scripted_returns["info"] = {"capabilities": {"inlinePageBreak": True}}
|
|
114
|
+
paragraph = Paragraph(session=mock_session, node_id="p-1", text_len=0)
|
|
115
|
+
alone = paragraph.add_run()
|
|
116
|
+
alone.add_break(WD_BREAK.PAGE)
|
|
117
|
+
|
|
118
|
+
alone.clear()
|
|
119
|
+
|
|
120
|
+
assert list(alone.iter_inner_content()) == [""]
|
|
121
|
+
assert _replaces(fake_sd_methods) == []
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _kinds(paragraph: Any) -> list[list[Any]]:
|
|
125
|
+
"""Each run's inner content, a picture as ``"Drawing"``."""
|
|
126
|
+
from docx.drawing import Drawing
|
|
127
|
+
|
|
128
|
+
return [
|
|
129
|
+
["Drawing" if isinstance(item, Drawing) else item for item in run.iter_inner_content()]
|
|
130
|
+
for run in paragraph.runs
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_a_run_of_a_page_break_and_a_picture_yields_the_breaks_text_where_it_stands() -> None:
|
|
135
|
+
# `<w:r><w:br w:type="page"/><w:drawing/></w:r>`: python-docx 1.2.0 yields ["", Drawing];
|
|
136
|
+
# `<w:r><w:drawing/><w:br w:type="page"/></w:r>`: [Drawing, ""].
|
|
137
|
+
picture = {"offset": 0, "drawing": {"imageId": "p1:0:abc"}}
|
|
138
|
+
p = _make_paragraph(
|
|
139
|
+
[
|
|
140
|
+
{"run": {"text": "Before."}},
|
|
141
|
+
{"run": {"text": "", "break": "page", "pictures": [picture], "emptyTextAfterPictures": [0]}},
|
|
142
|
+
{"run": {"text": "", "break": "page", "pictures": [picture], "emptyTextAfterPictures": [1]}},
|
|
143
|
+
]
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
assert _kinds(p) == [["Before."], ["", "Drawing"], ["Drawing", ""]]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_a_break_on_each_side_of_a_picture_yields_empty_text_on_each_side() -> None:
|
|
150
|
+
# `<w:r><w:br w:type="page"/><w:drawing/><w:br w:type="page"/></w:r>`: python-docx 1.2.0
|
|
151
|
+
# yields ["", Drawing, ""].
|
|
152
|
+
picture = {"offset": 0, "drawing": {"imageId": "p1:0:abc"}}
|
|
153
|
+
p = _make_paragraph(
|
|
154
|
+
[{"run": {"text": "", "break": "page", "pictures": [picture], "emptyTextAfterPictures": [0, 1]}}]
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
assert _kinds(p) == [["", "Drawing", ""]]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_text_then_a_picture_then_a_page_break_yields_the_breaks_text_after_the_picture() -> None:
|
|
161
|
+
# `<w:r><w:t>Logo</w:t><w:drawing/><w:br w:type="page"/></w:r>`: ["Logo", Drawing, ""].
|
|
162
|
+
picture = {"offset": 4, "drawing": {"imageId": "p1:0:abc"}}
|
|
163
|
+
p = _make_paragraph([{"run": {"text": "Logo", "pictures": [picture], "emptyTextAfterPictures": [1]}}])
|
|
164
|
+
|
|
165
|
+
assert _kinds(p) == [["Logo", "Drawing", ""]]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_without_the_breaks_place_its_text_comes_before_the_pictures() -> None:
|
|
169
|
+
# A docx-studio before `emptyTextAfterPictures`: the break first, as a page that opens with the picture.
|
|
170
|
+
picture = {"offset": 0, "drawing": {"imageId": "p1:0:abc"}}
|
|
171
|
+
p = _make_paragraph([{"run": {"text": "", "break": "page", "pictures": [picture]}}])
|
|
172
|
+
|
|
173
|
+
assert _kinds(p) == [["", "Drawing"]]
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_a_run_of_text_and_a_picture_yields_no_empty_text() -> None:
|
|
177
|
+
picture = {"offset": 4, "drawing": {"imageId": "p1:0:abc"}}
|
|
178
|
+
p = _make_paragraph([{"run": {"text": "Logo", "pictures": [picture]}}])
|
|
179
|
+
|
|
180
|
+
assert _kinds(p) == [["Logo", "Drawing"]]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
PNG = bytes.fromhex(
|
|
184
|
+
"89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489"
|
|
185
|
+
"0000000d4944415478da63f8ffff3f0005fe02fea7d6a4b60000000049454e44ae426082"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _live_paragraph(mock_session: Any, fake_sd_methods: Any) -> Any:
|
|
190
|
+
from docx.text.paragraph import Paragraph
|
|
191
|
+
|
|
192
|
+
fake_sd_methods.scripted_returns["info"] = {
|
|
193
|
+
"capabilities": {"inlinePageBreak": True, "pictureRuns": True, "runIdentity": True}
|
|
194
|
+
}
|
|
195
|
+
fake_sd_methods.scripted_returns["create.image"] = {"nodeId": "p-1", "image": {"nodeId": "p-1:0:cc"}}
|
|
196
|
+
return Paragraph(session=mock_session, node_id="p-1", text_len=0)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _live_kinds(run: Any) -> list[Any]:
|
|
200
|
+
from docx.drawing import Drawing
|
|
201
|
+
|
|
202
|
+
return ["Drawing" if isinstance(item, Drawing) else item for item in run.iter_inner_content()]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_the_run_add_break_then_add_picture_built_yields_the_breaks_text_first(
|
|
206
|
+
mock_session: Any, fake_sd_methods: Any
|
|
207
|
+
) -> None:
|
|
208
|
+
# python-docx: `r = p.add_run(); r.add_break(PAGE); r.add_picture(png)` → ["", Drawing].
|
|
209
|
+
import io
|
|
210
|
+
|
|
211
|
+
from docx.enum.text import WD_BREAK
|
|
212
|
+
|
|
213
|
+
run = _live_paragraph(mock_session, fake_sd_methods).add_run()
|
|
214
|
+
run.add_break(WD_BREAK.PAGE)
|
|
215
|
+
run.add_picture(io.BytesIO(PNG))
|
|
216
|
+
|
|
217
|
+
assert _live_kinds(run) == ["", "Drawing"]
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def test_the_run_add_picture_then_add_break_built_yields_the_breaks_text_last(
|
|
221
|
+
mock_session: Any, fake_sd_methods: Any
|
|
222
|
+
) -> None:
|
|
223
|
+
# python-docx: `r.add_picture(png); r.add_break(PAGE)` → [Drawing, ""]; one more picture, then
|
|
224
|
+
# a column break: [Drawing, "", Drawing, ""].
|
|
225
|
+
import io
|
|
226
|
+
|
|
227
|
+
from docx.enum.text import WD_BREAK
|
|
228
|
+
|
|
229
|
+
run = _live_paragraph(mock_session, fake_sd_methods).add_run()
|
|
230
|
+
run.add_picture(io.BytesIO(PNG))
|
|
231
|
+
run.add_break(WD_BREAK.PAGE)
|
|
232
|
+
|
|
233
|
+
assert _live_kinds(run) == ["Drawing", ""]
|
|
234
|
+
|
|
235
|
+
run.add_picture(io.BytesIO(PNG))
|
|
236
|
+
run.add_break(WD_BREAK.COLUMN)
|
|
237
|
+
|
|
238
|
+
assert _live_kinds(run) == ["Drawing", "", "Drawing", ""]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def test_a_break_on_each_side_of_a_picture_added_to_the_run_yields_empty_text_on_each_side(
|
|
242
|
+
mock_session: Any, fake_sd_methods: Any
|
|
243
|
+
) -> None:
|
|
244
|
+
import io
|
|
245
|
+
|
|
246
|
+
from docx.enum.text import WD_BREAK
|
|
247
|
+
|
|
248
|
+
run = _live_paragraph(mock_session, fake_sd_methods).add_run()
|
|
249
|
+
run.add_break(WD_BREAK.PAGE)
|
|
250
|
+
run.add_picture(io.BytesIO(PNG))
|
|
251
|
+
run.add_break(WD_BREAK.PAGE)
|
|
252
|
+
|
|
253
|
+
assert _live_kinds(run) == ["", "Drawing", ""]
|
|
254
|
+
|