athena-python-docx 0.35.0__tar.gz → 0.36.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.35.0 → athena_python_docx-0.36.0}/AGENTS.md +15 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/PKG-INFO +1 -1
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/__init__.py +1 -1
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_proxy.py +26 -2
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/commands.py +4 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/oxml/__init__.py +1 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/styles/latent.py +21 -4
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/styles/style.py +29 -10
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/table.py +7 -3
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/paragraph.py +9 -3
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/run.py +147 -46
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/tabstops.py +26 -3
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/pyproject.toml +1 -1
- athena_python_docx-0.36.0/tests/fidelity/ab_probe/agent_documents.py +133 -0
- athena_python_docx-0.36.0/tests/fidelity/ab_probe/picture_runs.py +101 -0
- athena_python_docx-0.36.0/tests/fidelity/ab_probe/return_types.py +44 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +1 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_inner_run_guard.py +5 -7
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_drawing_image.py +179 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_enum_parity.py +3 -1
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_latent_style_writes.py +21 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_identity.py +13 -11
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_tab_stops.py +35 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_tab_stop_writes.py +21 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/uv.lock +1 -1
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/.gitignore +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/CLAUDE.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/DOCX_EXEC_LAB.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/README.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_capabilities.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_citations.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_http.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_postproc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_references.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_run_order.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_tracked.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/_xml_text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/api.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/blkcntnr.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/charts.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/client.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/comments.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/document.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/drawing/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/base.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/dml.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/shape.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/style.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/errors.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/fields.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/image/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/image/exceptions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/image/image.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/math.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/section.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/session.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/settings.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/shape.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/shared.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/styles/_table.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/toc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/docx/typing.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/docx_exec_lab.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/scripts/validate_find_replace_asset.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/default_style_run_formatting.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/header_footer_pictures.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/less_used_writes.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/merged_cell_identity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/paragraph_text_setter.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/proxy_equality.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/xml_incompatible_text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe/zero_and_negative_indents.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw16_header_footer_tables.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw17_header_letterhead_filled.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw18_header_table_properties.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw19_header_table_rows_columns.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/op_snapshots/rw20_header_table_merges.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fixtures/field_reads.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fixtures/note_reference_reads.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fixtures/ruby_reads.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/fixtures/symbol_reads.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/baseline.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/fixture_scripts.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/reader.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/runner.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/sdk_driver.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/stock_driver.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/live/test_live_runner.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_add_section.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_alignment_values.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_athena_extension_creates_session_open.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_batch_chunking.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_battery_cases.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_borders_spec.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_fastpath_runs.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_merge.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_nested_tables.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_paragraphs_listed.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_citations.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_color_format_theme.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_commands.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_comment_paragraphs.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_comments_first_read.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_content_control_value.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_core_properties.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_document_settings_session_open.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_docx_exec_lab.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_empty_hyperlinks.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_export_docx_clean.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_export_rescue_anchors.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_field_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_field_refresh.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_field_runs.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_flushed_write_failures.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_inline_page_break.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_inline_shape_alt_text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_inline_shape_size.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_inline_shape_type.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_inline_shapes_floating.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_line_clear_break.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_merged_cell_identity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_missing_modules.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_nested_table_refused.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_note_reference_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_page_break.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_paragraph_delete.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_paragraph_indent_reads.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_paragraph_runs_hyperlinks.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_paragraph_text_empty_run.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_parfmt_clears.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_pdf_export_and_page_renders.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_postproc_ref_restore.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_proxy_equality.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_read_run_ranges.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_rendered_page_breaks.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_repeated_node_read.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_restart_numbering.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_round_trip_smoke_script.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_ruby_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_add_picture_anchor.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_break_inner_content.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_edges.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_formatting_wire.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_later_runs.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_mark_inheritance.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_page_number_blocks.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_table_style_objects.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_text_python_docx.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_text_refreshes_paragraph.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_run_unmodeled_toggles.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_sdk_reads_served.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_section_read_lengths.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_delete.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_formatting_writes.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_metadata_writes.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_names.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_style_tab_stops_read.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_symbol_reads_python_docx_parity.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_anchors.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_clears.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_direction.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_read_reuse.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_text_control_characters.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_tracked_revisions_offsets.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_unmapped_alignment_reads.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_uv_lock_version.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_xml_incompatible_text.py +0 -0
- {athena_python_docx-0.35.0 → athena_python_docx-0.36.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -121,6 +121,21 @@ pinned by focused tests and documented in
|
|
|
121
121
|
`horz_dpi`, `width`, `scaled_dimensions`, …). A picture in a table cell or
|
|
122
122
|
a header has no id to read its image by, so `.image` raises `ValueError`;
|
|
123
123
|
an older docx-studio does not report pictures, so they are not runs there.
|
|
124
|
+
`Run.add_picture` puts the picture in that run, as python-docx appends the
|
|
125
|
+
`w:drawing` to its `w:r`: after what the run holds, and text `add_text`
|
|
126
|
+
adds goes after it. Against a docx-studio that reports
|
|
127
|
+
`capabilities.pictureRuns`, `CreateImage` carries `runEdge: "append"` (the
|
|
128
|
+
run's identity as `add_text` names it), the run's record holds the picture
|
|
129
|
+
(`pictureRun`), and the run reads as one run whose pictures stand at their
|
|
130
|
+
places in its text (`pictures`), so `iter_inner_content()` yields its text
|
|
131
|
+
and each `Drawing` in order (with Word's rendered page breaks where the read
|
|
132
|
+
places them among the pictures, `afterPictures`), a whole-run format takes
|
|
133
|
+
its pictures too, and `run.text = ...` takes every one of them out
|
|
134
|
+
(`wholeRun`). A picture's run (no text) formats its picture at once, named
|
|
135
|
+
by its identity (`laterRuns`), so `r = p.add_run(); r.bold = True;
|
|
136
|
+
r.add_picture(img)` writes the bold `w:rPr` beside the `w:drawing`. An older
|
|
137
|
+
docx-studio puts the picture in a run of its own (`tests/test_drawing_image.py`,
|
|
138
|
+
battery `ab_probe/picture_runs.py`).
|
|
124
139
|
- **A run holding only a page or column break yields `""` from
|
|
125
140
|
`Run.iter_inner_content()`,** as python-docx reads a `w:br` of type `page`
|
|
126
141
|
or `column` as empty text; an empty run (a comment reference's) yields
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.36.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>
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
"""python-docx's ``ElementProxy`` equality, for the SDK's proxies of the
|
|
2
2
|
objects python-docx wraps in one: styles, the styles part, settings, a
|
|
3
|
-
paragraph's or a style's paragraph format, a run's or a style's font
|
|
3
|
+
paragraph's or a style's paragraph format, a run's or a style's font, tab
|
|
4
|
+
stops and the latent styles."""
|
|
4
5
|
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
7
8
|
import weakref
|
|
8
|
-
from
|
|
9
|
+
from collections.abc import Iterator
|
|
10
|
+
from typing import Any, Generic, TypeVar
|
|
11
|
+
|
|
12
|
+
_T = TypeVar("_T")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class IdentityWeakSet(Generic[_T]):
|
|
16
|
+
"""A set of objects held weakly, by identity: a ``weakref.WeakSet`` hashes
|
|
17
|
+
its members, and a proxy that compares by its element
|
|
18
|
+
(:class:`ElementProxyEquality`) is not hashable, as in python-docx."""
|
|
19
|
+
|
|
20
|
+
__slots__ = ("_members",)
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
self._members: "weakref.WeakValueDictionary[int, _T]" = weakref.WeakValueDictionary()
|
|
24
|
+
|
|
25
|
+
def add(self, item: _T) -> None:
|
|
26
|
+
self._members[id(item)] = item
|
|
27
|
+
|
|
28
|
+
def __iter__(self) -> Iterator[_T]:
|
|
29
|
+
return iter(list(self._members.values()))
|
|
30
|
+
|
|
31
|
+
def __len__(self) -> int:
|
|
32
|
+
return len(self._members)
|
|
9
33
|
|
|
10
34
|
|
|
11
35
|
class ElementProxyEquality:
|
|
@@ -140,6 +140,10 @@ class CreateImage(Command):
|
|
|
140
140
|
at: dict[str, Any]
|
|
141
141
|
client_node_id: str | None = None
|
|
142
142
|
run: dict[str, Any] | None = None
|
|
143
|
+
# ``"append"`` (``Run.add_picture`` against a docx-studio that reports
|
|
144
|
+
# ``capabilities.pictureRuns``): the picture ends the run that ends at the
|
|
145
|
+
# anchor's offset, in that run's ``w:r``, as python-docx appends it.
|
|
146
|
+
run_edge: str | None = None
|
|
143
147
|
|
|
144
148
|
|
|
145
149
|
@dataclass
|
|
@@ -92,6 +92,7 @@ _XML_ELEMENT_ATTRS: frozenset[str] = frozenset(
|
|
|
92
92
|
"_tc", # _Cell._tc
|
|
93
93
|
"_tbl", # Table._tbl
|
|
94
94
|
"_tr", # _Row._tr
|
|
95
|
+
"_t", # _Text._t (the ``w:t`` Run.add_text added)
|
|
95
96
|
"element", # Run.element / Paragraph.element / Document.element
|
|
96
97
|
"_element", # private alias used by some python-docx forks
|
|
97
98
|
},
|
|
@@ -23,6 +23,7 @@ import warnings
|
|
|
23
23
|
import weakref
|
|
24
24
|
from typing import TYPE_CHECKING, Any, Iterator
|
|
25
25
|
|
|
26
|
+
from docx._proxy import ElementProxyEquality, IdentityWeakSet
|
|
26
27
|
from docx.styles import BabelFish
|
|
27
28
|
|
|
28
29
|
if TYPE_CHECKING:
|
|
@@ -52,12 +53,12 @@ _XML_INCOMPATIBLE_MESSAGE = (
|
|
|
52
53
|
# Session -> every live ``_LatentStyle``, read or added: deleting one moves the
|
|
53
54
|
# others of its name after it up one place (:func:`_removed`), as python-docx's
|
|
54
55
|
# are elements a deletion elsewhere does not move. The sets hold them weakly.
|
|
55
|
-
_LIVE: "weakref.WeakKeyDictionary[Any,
|
|
56
|
+
_LIVE: "weakref.WeakKeyDictionary[Any, IdentityWeakSet[_LatentStyle]]" = weakref.WeakKeyDictionary()
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
def _track(latent_style: "_LatentStyle") -> None:
|
|
59
60
|
try:
|
|
60
|
-
_LIVE.setdefault(latent_style._session,
|
|
61
|
+
_LIVE.setdefault(latent_style._session, IdentityWeakSet()).add(latent_style)
|
|
61
62
|
except TypeError: # no session, or one that takes no weak reference
|
|
62
63
|
return
|
|
63
64
|
|
|
@@ -67,6 +68,7 @@ def _removed(deleted: "_LatentStyle", name: Any) -> None:
|
|
|
67
68
|
that name after it move up one place, and another object of the same
|
|
68
69
|
exception is out of the document, writing nothing to it, as python-docx's
|
|
69
70
|
removed element is."""
|
|
71
|
+
deleted._element = removed = object()
|
|
70
72
|
try:
|
|
71
73
|
live = _LIVE.get(deleted._session)
|
|
72
74
|
except TypeError:
|
|
@@ -78,6 +80,7 @@ def _removed(deleted: "_LatentStyle", name: Any) -> None:
|
|
|
78
80
|
continue
|
|
79
81
|
if other._occurrence == deleted._occurrence:
|
|
80
82
|
other._detached = True
|
|
83
|
+
other._element = removed
|
|
81
84
|
elif other._occurrence > deleted._occurrence:
|
|
82
85
|
other._occurrence -= 1
|
|
83
86
|
|
|
@@ -140,13 +143,17 @@ def _int(text: object) -> int | None:
|
|
|
140
143
|
return None
|
|
141
144
|
|
|
142
145
|
|
|
143
|
-
class LatentStyles:
|
|
146
|
+
class LatentStyles(ElementProxyEquality):
|
|
144
147
|
"""The default behaviors for latent styles in this document, and the
|
|
145
148
|
|_LatentStyle| objects that override them for a named latent style."""
|
|
146
149
|
|
|
147
150
|
def __init__(self, *, session: "Session | None" = None) -> None:
|
|
148
151
|
self._session: "Session | None" = session
|
|
149
152
|
|
|
153
|
+
def _proxy_element(self) -> tuple[object, ...]:
|
|
154
|
+
# python-docx's LatentStyles wraps the styles part's w:latentStyles.
|
|
155
|
+
return ("w:latentStyles", self._session)
|
|
156
|
+
|
|
150
157
|
def _read(self, prop: str | None) -> dict[str, Any]:
|
|
151
158
|
"""The latent styles docx-studio reports; a read of ``prop`` from one
|
|
152
159
|
that reports none warns (iterating, an empty collection, does not)."""
|
|
@@ -246,7 +253,7 @@ class LatentStyles:
|
|
|
246
253
|
self._set_default("load_count", "count", None if value is None else int(value))
|
|
247
254
|
|
|
248
255
|
|
|
249
|
-
class _LatentStyle:
|
|
256
|
+
class _LatentStyle(ElementProxyEquality):
|
|
250
257
|
"""A ``w:lsdException``: display behaviors for a built-in style the
|
|
251
258
|
document does not define yet, overriding the |LatentStyles| defaults."""
|
|
252
259
|
|
|
@@ -260,8 +267,18 @@ class _LatentStyle:
|
|
|
260
267
|
#: Removed through another object of the same exception: like
|
|
261
268
|
#: python-docx's element out of the part, it writes nothing to the document.
|
|
262
269
|
self._detached = False
|
|
270
|
+
#: The exception it held once removed, which its other objects hold too.
|
|
271
|
+
self._element: object | None = None
|
|
263
272
|
_track(self)
|
|
264
273
|
|
|
274
|
+
def _proxy_element(self) -> tuple[object, ...]:
|
|
275
|
+
# python-docx's _LatentStyle wraps its w:lsdException: the exception
|
|
276
|
+
# of its name at its place among them, or, removed, that exception, as
|
|
277
|
+
# its other objects are.
|
|
278
|
+
if self._detached or self._exception is None:
|
|
279
|
+
return ("w:lsdException", self._element if self._element is not None else id(self))
|
|
280
|
+
return ("w:lsdException", self._session, self._exception.get("name"), self._occurrence)
|
|
281
|
+
|
|
265
282
|
def _target(self) -> dict[str, Any]:
|
|
266
283
|
"""The exception's address in ``EditLatentStyles``."""
|
|
267
284
|
name = self._exception.get("name")
|
|
@@ -35,6 +35,7 @@ from docx._batching import run_sync
|
|
|
35
35
|
from docx._buffer import writes_unapplied
|
|
36
36
|
from docx._proxy import (
|
|
37
37
|
ElementProxyEquality,
|
|
38
|
+
IdentityWeakSet,
|
|
38
39
|
style_definition,
|
|
39
40
|
style_deleted,
|
|
40
41
|
style_element,
|
|
@@ -910,11 +911,13 @@ class _StyleParagraphFormat(ElementProxyEquality):
|
|
|
910
911
|
|
|
911
912
|
_TAB_STOPS_REASON = "does not write this style's tab stops: it predates styleTabStops, or does not write the style's formatting"
|
|
912
913
|
|
|
913
|
-
# Session -> style
|
|
914
|
-
# write moves the others to their new places in
|
|
915
|
-
# (``_StyleTabStops._moved``), as python-docx's are elements
|
|
916
|
-
# another does not move.
|
|
917
|
-
|
|
914
|
+
# Session -> style definition (``style_element``) -> every live tab stop of
|
|
915
|
+
# that style, read or added: a write moves the others to their new places in
|
|
916
|
+
# the style's list (``_StyleTabStops._moved``), as python-docx's are elements
|
|
917
|
+
# that a change to another does not move. By the definition, not the id: a
|
|
918
|
+
# renamed style keeps its stops, and one made after a style of its id was
|
|
919
|
+
# deleted holds none of the deleted one's. The sets hold them weakly.
|
|
920
|
+
_LIVE_TAB_STOPS: "weakref.WeakKeyDictionary[Any, dict[tuple[object, ...], IdentityWeakSet[_StyleTabStop]]]" = (
|
|
918
921
|
weakref.WeakKeyDictionary()
|
|
919
922
|
)
|
|
920
923
|
|
|
@@ -926,7 +929,7 @@ _REMOVED = "removed"
|
|
|
926
929
|
_CLEARED = "cleared"
|
|
927
930
|
|
|
928
931
|
|
|
929
|
-
class _StyleTabStop:
|
|
932
|
+
class _StyleTabStop(ElementProxyEquality):
|
|
930
933
|
"""One tab stop of a style's ``w:tabs``, as python-docx's ``TabStop``
|
|
931
934
|
reads it: ``position`` a ``Length``, ``alignment`` a
|
|
932
935
|
``WD_TAB_ALIGNMENT`` (a cleared tab's is ``CLEAR``), ``leader`` a
|
|
@@ -938,7 +941,7 @@ class _StyleTabStop:
|
|
|
938
941
|
to another tab stop moves, as python-docx's ``w:tab`` element stays itself;
|
|
939
942
|
one the style no longer holds writes nothing, as a removed element."""
|
|
940
943
|
|
|
941
|
-
__slots__ = ("__weakref__", "_detached", "_entry", "_index", "_owner")
|
|
944
|
+
__slots__ = ("__weakref__", "_detached", "_element", "_entry", "_index", "_owner")
|
|
942
945
|
|
|
943
946
|
def __init__(
|
|
944
947
|
self, entry: dict[str, Any], owner: "_StyleTabStops | None" = None, index: int | None = None
|
|
@@ -947,9 +950,19 @@ class _StyleTabStop:
|
|
|
947
950
|
self._owner: "_StyleTabStops | None" = owner
|
|
948
951
|
self._index: int | None = index
|
|
949
952
|
self._detached: str | None = None
|
|
953
|
+
# The w:tab it held once out of the style, which its other objects hold too.
|
|
954
|
+
self._element: object | None = None
|
|
950
955
|
if owner is not None and index is not None:
|
|
951
956
|
owner._track(self)
|
|
952
957
|
|
|
958
|
+
def _proxy_element(self) -> tuple[object, ...]:
|
|
959
|
+
# python-docx's TabStop wraps its w:tab: a stop at its place in the
|
|
960
|
+
# style's list is that w:tab; one out of the style is the w:tab taken
|
|
961
|
+
# out, as are its other objects.
|
|
962
|
+
if self._owner is not None and self._index is not None and not self._detached:
|
|
963
|
+
return ("w:tab", *style_element(self._owner._style), self._index)
|
|
964
|
+
return ("w:tab", self._element if self._element is not None else id(self))
|
|
965
|
+
|
|
953
966
|
def _wire(self) -> dict[str, Any]:
|
|
954
967
|
"""This tab stop as ``SetStyleFormatting``'s ``tabStops`` takes it."""
|
|
955
968
|
leader = self._entry.get("leader")
|
|
@@ -1010,7 +1023,7 @@ class _StyleTabStop:
|
|
|
1010
1023
|
)
|
|
1011
1024
|
|
|
1012
1025
|
|
|
1013
|
-
class _StyleTabStops:
|
|
1026
|
+
class _StyleTabStops(ElementProxyEquality):
|
|
1014
1027
|
"""``ParagraphStyle.paragraph_format.tab_stops``: python-docx's
|
|
1015
1028
|
``TabStops`` over the style's own ``w:tabs``.
|
|
1016
1029
|
|
|
@@ -1030,6 +1043,10 @@ class _StyleTabStops:
|
|
|
1030
1043
|
def __init__(self, style: "BaseStyle") -> None:
|
|
1031
1044
|
self._style: "BaseStyle" = style
|
|
1032
1045
|
|
|
1046
|
+
def _proxy_element(self) -> tuple[object, ...]:
|
|
1047
|
+
# python-docx's TabStops wraps the style's w:pPr (its paragraph format wraps the w:style).
|
|
1048
|
+
return ("w:pPr", *style_element(self._style))
|
|
1049
|
+
|
|
1033
1050
|
def _stashed(self) -> list:
|
|
1034
1051
|
kept = self._style._overrides
|
|
1035
1052
|
if "parfmt.tab_stops" not in kept:
|
|
@@ -1052,7 +1069,7 @@ class _StyleTabStops:
|
|
|
1052
1069
|
styles = _LIVE_TAB_STOPS.setdefault(self._style._session, {})
|
|
1053
1070
|
except TypeError: # no session, or one that takes no weak reference
|
|
1054
1071
|
return
|
|
1055
|
-
styles.setdefault(self._style
|
|
1072
|
+
styles.setdefault(style_element(self._style), IdentityWeakSet()).add(stop)
|
|
1056
1073
|
|
|
1057
1074
|
def _moved(
|
|
1058
1075
|
self,
|
|
@@ -1066,15 +1083,17 @@ class _StyleTabStops:
|
|
|
1066
1083
|
new place) gives one, or out of the style (``why``) where ``place``
|
|
1067
1084
|
gives none."""
|
|
1068
1085
|
try:
|
|
1069
|
-
live = (_LIVE_TAB_STOPS.get(self._style._session) or {}).get(self._style
|
|
1086
|
+
live = (_LIVE_TAB_STOPS.get(self._style._session) or {}).get(style_element(self._style))
|
|
1070
1087
|
except TypeError:
|
|
1071
1088
|
return
|
|
1089
|
+
gone: dict[int, object] = {}
|
|
1072
1090
|
for stop in list(live or ()):
|
|
1073
1091
|
if stop._detached or stop._index is None:
|
|
1074
1092
|
continue
|
|
1075
1093
|
new = place(stop._index)
|
|
1076
1094
|
if new is None:
|
|
1077
1095
|
stop._detached = why
|
|
1096
|
+
stop._element = gone.setdefault(stop._index, object())
|
|
1078
1097
|
continue
|
|
1079
1098
|
stop._index = new
|
|
1080
1099
|
if entries and new in entries:
|
|
@@ -321,6 +321,7 @@ if TYPE_CHECKING:
|
|
|
321
321
|
WD_TABLE_ALIGNMENT,
|
|
322
322
|
WD_TABLE_DIRECTION,
|
|
323
323
|
)
|
|
324
|
+
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
|
324
325
|
from docx.styles.style import ParagraphStyle, _TableStyle
|
|
325
326
|
from docx.text.paragraph import Paragraph
|
|
326
327
|
|
|
@@ -1224,14 +1225,17 @@ class Table:
|
|
|
1224
1225
|
run_sync(self._session.doc.tables.set_style(params))
|
|
1225
1226
|
|
|
1226
1227
|
@property
|
|
1227
|
-
def alignment(self) -> "
|
|
1228
|
-
|
|
1228
|
+
def alignment(self) -> "WD_PARAGRAPH_ALIGNMENT | None":
|
|
1229
|
+
"""The table's ``w:jc``, as python-docx 1.2.0 reads it: through the
|
|
1230
|
+
paragraph ``CT_Jc``, so a member of ``WD_PARAGRAPH_ALIGNMENT``, which
|
|
1231
|
+
compares equal to the ``WD_TABLE_ALIGNMENT`` member of its value."""
|
|
1232
|
+
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
|
1229
1233
|
|
|
1230
1234
|
info: object = run_sync(
|
|
1231
1235
|
self._session.doc.tables.get_properties({"nodeId": self._fresh_node_id()}),
|
|
1232
1236
|
)
|
|
1233
1237
|
if isinstance(info, dict):
|
|
1234
|
-
return
|
|
1238
|
+
return WD_PARAGRAPH_ALIGNMENT.from_docx_studio(info.get("alignment"))
|
|
1235
1239
|
return None
|
|
1236
1240
|
|
|
1237
1241
|
@alignment.setter
|
|
@@ -245,9 +245,15 @@ def _node_text(session: "Session", node_id: str, *, final: bool = False) -> str:
|
|
|
245
245
|
|
|
246
246
|
def _picture_run_data(inline: dict, drawing: dict) -> dict:
|
|
247
247
|
"""The run data of a picture's inline (``{drawing}``): its ``w:r`` holds the
|
|
248
|
-
picture and no text,
|
|
249
|
-
which stand before its drawing (``renderedPageBreaks``)
|
|
250
|
-
|
|
248
|
+
picture and no text, the rendered page breaks docx-studio reads in it,
|
|
249
|
+
which stand before its drawing (``renderedPageBreaks``), and the run's
|
|
250
|
+
formatting it reads (its ``w:rPr``, which python-docx reads beside the
|
|
251
|
+
``w:drawing``)."""
|
|
252
|
+
from docx.text.run import _RUN_READ_KEYS
|
|
253
|
+
|
|
254
|
+
data: dict = {key: value for key, value in inline.items() if key in _RUN_READ_KEYS}
|
|
255
|
+
data["text"] = ""
|
|
256
|
+
data["drawing"] = drawing
|
|
251
257
|
breaks: object = inline.get("renderedPageBreaks")
|
|
252
258
|
if isinstance(breaks, list):
|
|
253
259
|
data["renderedPageBreaks"] = breaks
|
|
@@ -463,6 +463,28 @@ class Run:
|
|
|
463
463
|
return None
|
|
464
464
|
return self._later_runs()
|
|
465
465
|
|
|
466
|
+
def _picture_run_identity(self) -> int | None:
|
|
467
|
+
"""This run's identity (:meth:`_later_runs`) while it holds a picture
|
|
468
|
+
and no text (a picture's run, ``drawing``), which a whole-run
|
|
469
|
+
``FormatApply`` of its collapsed range formats, untracked, on a
|
|
470
|
+
docx-studio that reports ``capabilities.pictureRuns``: python-docx
|
|
471
|
+
formats the run's ``w:r``, and docx-studio its picture. Else None."""
|
|
472
|
+
if not self._is_collapsed_range or tracking(self._session):
|
|
473
|
+
return None
|
|
474
|
+
drawing = self._inline_snapshot.get("drawing")
|
|
475
|
+
if not isinstance(drawing, dict) or drawing.get("legacy") is True:
|
|
476
|
+
return None
|
|
477
|
+
if not server_takes(self._session, "pictureRuns"):
|
|
478
|
+
return None
|
|
479
|
+
return self._later_runs()
|
|
480
|
+
|
|
481
|
+
def _empty_run_identity(self) -> int | None:
|
|
482
|
+
"""The identity by which a whole-run ``FormatApply`` of this run's
|
|
483
|
+
collapsed range formats what it holds: a page or column break's
|
|
484
|
+
(:meth:`_break_run_identity`) or a picture's (:meth:`_picture_run_identity`)."""
|
|
485
|
+
identity = self._break_run_identity()
|
|
486
|
+
return identity if identity is not None else self._picture_run_identity()
|
|
487
|
+
|
|
466
488
|
def _add_run_ref(self, command: dict) -> dict:
|
|
467
489
|
"""Add the run identity of an insert at the end of this run.
|
|
468
490
|
|
|
@@ -707,9 +729,10 @@ class Run:
|
|
|
707
729
|
pending = getattr(self, "_pending_inline", None)
|
|
708
730
|
if not pending:
|
|
709
731
|
return
|
|
710
|
-
# An empty run that holds a page or column break
|
|
711
|
-
# the
|
|
712
|
-
|
|
732
|
+
# An empty run that holds a page or column break, or a picture:
|
|
733
|
+
# docx-studio formats the run's break or picture, which it tells by
|
|
734
|
+
# the run's identity.
|
|
735
|
+
identity = self._empty_run_identity()
|
|
713
736
|
if self._is_collapsed_range and identity is None:
|
|
714
737
|
return
|
|
715
738
|
self._pending_inline = {}
|
|
@@ -724,7 +747,7 @@ class Run:
|
|
|
724
747
|
},
|
|
725
748
|
),
|
|
726
749
|
)
|
|
727
|
-
# Its break holds the formatting now, which what it takes next continues.
|
|
750
|
+
# Its break or picture holds the formatting now, which what it takes next continues.
|
|
728
751
|
self._fresh = False
|
|
729
752
|
return
|
|
730
753
|
# An emptied run's kept formatting turns off each toggle it did not
|
|
@@ -827,6 +850,43 @@ class Run:
|
|
|
827
850
|
yield Drawing(session=self._session, info=drawing)
|
|
828
851
|
if not self._raw_text():
|
|
829
852
|
return
|
|
853
|
+
pictures = self._pictures()
|
|
854
|
+
if pictures:
|
|
855
|
+
from docx.drawing import Drawing
|
|
856
|
+
|
|
857
|
+
# A run that holds pictures beside its text (``run.add_picture``
|
|
858
|
+
# appends a ``w:drawing`` to the run): the text between them, each
|
|
859
|
+
# picture and each of Word's rendered page breaks, in order. Where
|
|
860
|
+
# a break and a picture stand at one place in the text, the read
|
|
861
|
+
# says how many of the run's pictures come before the break
|
|
862
|
+
# (``afterPictures``); without it the break comes first, as Word
|
|
863
|
+
# writes a page that opens with the picture.
|
|
864
|
+
raw = self._raw_text()
|
|
865
|
+
font = self._symbol_font() if _SYMBOL_CHARACTERS.search(raw) else None
|
|
866
|
+
items: list[tuple[int, float, dict, bool]] = [
|
|
867
|
+
(offset, index, info, True) for index, (offset, info) in enumerate(pictures)
|
|
868
|
+
]
|
|
869
|
+
rendered = self._rendered_page_breaks()
|
|
870
|
+
for info in rendered:
|
|
871
|
+
offset = int(info.get("offset", 0) or 0)
|
|
872
|
+
after = info.get("afterPictures")
|
|
873
|
+
if not isinstance(after, int) or isinstance(after, bool):
|
|
874
|
+
after = sum(1 for at, _ in pictures if at < offset)
|
|
875
|
+
items.append((offset, after - 0.5, info, False))
|
|
876
|
+
items.sort(key=lambda item: (item[0], item[1]))
|
|
877
|
+
cut = 0
|
|
878
|
+
for offset, _order, info, is_picture in items:
|
|
879
|
+
at = min(max(offset, cut), len(raw))
|
|
880
|
+
if _word_text(raw[cut:at], font):
|
|
881
|
+
yield _word_text(raw[cut:at], font)
|
|
882
|
+
if not is_picture:
|
|
883
|
+
yield RenderedPageBreak(paragraph=self._page_break_paragraph(), offset=self._range[0] + at, info=info)
|
|
884
|
+
elif info.get("legacy") is not True:
|
|
885
|
+
yield Drawing(session=self._session, info=info)
|
|
886
|
+
cut = at
|
|
887
|
+
if _word_text(raw[cut:], font):
|
|
888
|
+
yield _word_text(raw[cut:], font)
|
|
889
|
+
return
|
|
830
890
|
if _note_reference(self._inline_snapshot):
|
|
831
891
|
return
|
|
832
892
|
text = _without_ruby(self._raw_text(), self._inline_snapshot)
|
|
@@ -923,18 +983,18 @@ class Run:
|
|
|
923
983
|
return
|
|
924
984
|
self._fastpath_text = None # type: ignore[attr-defined]
|
|
925
985
|
self._inline_snapshot.pop("renderedPageBreaks", None)
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
# python-docx replaces all of the run's content, its picture too.
|
|
986
|
+
pictures: list[str] = self._picture_ids()
|
|
987
|
+
if pictures:
|
|
988
|
+
# python-docx replaces all of the run's content, its pictures too.
|
|
930
989
|
old_range: tuple[int, int] = self._range
|
|
931
990
|
tracked: bool = tracking(self._session)
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
)
|
|
991
|
+
replace: dict = {"target": self._text_range, "text": value, "removePictures": pictures}
|
|
992
|
+
if server_takes(self._session, "pictureRuns"):
|
|
993
|
+
# All of this run: its record then holds the new text alone.
|
|
994
|
+
replace["wholeRun"] = True
|
|
995
|
+
run_sync(self._session.doc.replace(replace))
|
|
937
996
|
self._inline_snapshot.pop("drawing", None)
|
|
997
|
+
self._inline_snapshot.pop("pictures", None)
|
|
938
998
|
if tracked:
|
|
939
999
|
self._note_tracked_replacement(old_range, value)
|
|
940
1000
|
else:
|
|
@@ -1029,8 +1089,11 @@ class Run:
|
|
|
1029
1089
|
# any pending inline formatting now that there's text to mark.
|
|
1030
1090
|
self._flush_pending_inline()
|
|
1031
1091
|
|
|
1032
|
-
def add_text(self, text: str) -> "
|
|
1033
|
-
"""
|
|
1092
|
+
def add_text(self, text: str) -> "_Text":
|
|
1093
|
+
"""Append ``text`` to the run, as python-docx does: its tabs and line
|
|
1094
|
+
breaks stay characters. Returns a |_Text| for the added text, as
|
|
1095
|
+
python-docx returns one for the ``w:t`` it adds: it has no public
|
|
1096
|
+
API."""
|
|
1034
1097
|
check_xml_compatible(text)
|
|
1035
1098
|
if not isinstance(text, str):
|
|
1036
1099
|
raise TypeError(
|
|
@@ -1039,34 +1102,10 @@ class Run:
|
|
|
1039
1102
|
)
|
|
1040
1103
|
self._refuse_field_write("add_text")
|
|
1041
1104
|
if self._check_cell_inner("add_text"):
|
|
1042
|
-
|
|
1043
|
-
# ops on the result also short-circuit cleanly. Propagate
|
|
1044
|
-
# the parent's cell_ooxml_address so any subsequent run-
|
|
1045
|
-
# format setter (``.bold = True`` etc.) can stash to the
|
|
1046
|
-
# right cell in ``_post_export_ops`` instead of dropping
|
|
1047
|
-
# silently.
|
|
1048
|
-
return Run(
|
|
1049
|
-
session=self._session,
|
|
1050
|
-
block_id=self._block_id,
|
|
1051
|
-
range_=(self._range[1], self._range[1]),
|
|
1052
|
-
paragraph=self._paragraph,
|
|
1053
|
-
in_cell=True,
|
|
1054
|
-
cell_ooxml_address=getattr(self, "_cell_ooxml_address", None),
|
|
1055
|
-
)
|
|
1105
|
+
return _Text(self)
|
|
1056
1106
|
self._fastpath_text = None # type: ignore[attr-defined]
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
session=self._session,
|
|
1060
|
-
block_id=self._block_id,
|
|
1061
|
-
range_=new_range,
|
|
1062
|
-
paragraph=self._paragraph,
|
|
1063
|
-
in_cell=self._in_cell,
|
|
1064
|
-
cell_ooxml_address=getattr(self, "_cell_ooxml_address", None),
|
|
1065
|
-
)
|
|
1066
|
-
# The added text is part of this run: when it grows, this run grows
|
|
1067
|
-
# (also through a chain of returned runs).
|
|
1068
|
-
added._owner_record = getattr(self, "_run_record", None) or getattr(self, "_owner_record", None)
|
|
1069
|
-
return added
|
|
1107
|
+
self._append_text(text)
|
|
1108
|
+
return _Text(self)
|
|
1070
1109
|
|
|
1071
1110
|
def _append_text(self, text: str) -> tuple[int, int]:
|
|
1072
1111
|
"""Insert ``text`` at the end of this run; return the new text's range."""
|
|
@@ -1440,12 +1479,57 @@ class Run:
|
|
|
1440
1479
|
create: dict = {"src": data_uri, "size": {"width": w_px, "height": h_px}, "at": at}
|
|
1441
1480
|
if at["kind"] == "selection":
|
|
1442
1481
|
self._add_run_ref(create)
|
|
1482
|
+
if server_takes(self._session, "pictureRuns"):
|
|
1483
|
+
# python-docx appends the ``w:drawing`` to this run's ``w:r``.
|
|
1484
|
+
self._mark_append(create)
|
|
1443
1485
|
result: object = run_sync(self._session.doc.create.image(create))
|
|
1444
1486
|
info: dict = _build_inline_shape_info(result, width=w_pt, height=h_pt)
|
|
1445
1487
|
if at["kind"] == "selection" and info.get("nodeId"):
|
|
1446
1488
|
note_picture(self, info["nodeId"], self._range[1], before=_before_image(create))
|
|
1489
|
+
if create.get("runEdge") == "append":
|
|
1490
|
+
self._hold_picture({"imageId": info["nodeId"]})
|
|
1491
|
+
# The formatting set on the run while it was empty is its
|
|
1492
|
+
# ``w:rPr``, which python-docx writes beside the picture.
|
|
1493
|
+
self._flush_pending_inline()
|
|
1447
1494
|
return InlineShape(session=self._session, info=info)
|
|
1448
1495
|
|
|
1496
|
+
def _pictures(self) -> list[tuple[int, dict]]:
|
|
1497
|
+
"""The pictures this run holds beside its text (``pictures``, which a
|
|
1498
|
+
docx-studio reporting ``capabilities.pictureRuns`` reads): each one's
|
|
1499
|
+
place in the run's text, in characters, and its drawing, in order."""
|
|
1500
|
+
held: object = self._inline_snapshot.get("pictures")
|
|
1501
|
+
pictures: list[tuple[int, dict]] = []
|
|
1502
|
+
for entry in held if isinstance(held, list) else []:
|
|
1503
|
+
drawing: object = entry.get("drawing") if isinstance(entry, dict) else None
|
|
1504
|
+
if not isinstance(drawing, dict):
|
|
1505
|
+
continue
|
|
1506
|
+
offset: object = entry.get("offset")
|
|
1507
|
+
valid = isinstance(offset, int) and not isinstance(offset, bool)
|
|
1508
|
+
pictures.append((offset if valid else 0, drawing)) # type: ignore[arg-type]
|
|
1509
|
+
return pictures
|
|
1510
|
+
|
|
1511
|
+
def _picture_ids(self) -> list[str]:
|
|
1512
|
+
"""The id of each picture this run holds: a picture run's (``drawing``)
|
|
1513
|
+
and those beside its text (``pictures``)."""
|
|
1514
|
+
drawings = [self._inline_snapshot.get("drawing"), *(info for _, info in self._pictures())]
|
|
1515
|
+
ids = [d.get("imageId") for d in drawings if isinstance(d, dict)]
|
|
1516
|
+
return [i for i in ids if isinstance(i, str) and i]
|
|
1517
|
+
|
|
1518
|
+
def _hold_picture(self, drawing: dict) -> None:
|
|
1519
|
+
"""This run took the picture ``drawing`` at its end (``run.add_picture``),
|
|
1520
|
+
as the next read gives it: a run of a picture alone as a picture's run
|
|
1521
|
+
(``drawing``), else among its pictures (``pictures``) where its text ends."""
|
|
1522
|
+
snapshot = self._inline_snapshot
|
|
1523
|
+
held = self._pictures()
|
|
1524
|
+
alone = snapshot.get("drawing")
|
|
1525
|
+
if not held and not self._raw_text() and not isinstance(alone, dict):
|
|
1526
|
+
snapshot["drawing"] = drawing
|
|
1527
|
+
return
|
|
1528
|
+
if isinstance(alone, dict):
|
|
1529
|
+
held = [(0, snapshot.pop("drawing"))]
|
|
1530
|
+
held.append((len(self._raw_text()), drawing))
|
|
1531
|
+
snapshot["pictures"] = [{"offset": offset, "drawing": info} for offset, info in held]
|
|
1532
|
+
|
|
1449
1533
|
@athena_extension(
|
|
1450
1534
|
issue=498,
|
|
1451
1535
|
description="Run.add_field — generic Word field (PAGE, DATE, REF, SEQ, TOC, ...).",
|
|
@@ -1901,10 +1985,11 @@ class Run:
|
|
|
1901
1985
|
)
|
|
1902
1986
|
return
|
|
1903
1987
|
self._note_inline_applied(kwargs)
|
|
1904
|
-
identity = self.
|
|
1988
|
+
identity = self._empty_run_identity()
|
|
1905
1989
|
if identity is not None:
|
|
1906
|
-
# The run holds only a page or column break: python-docx
|
|
1907
|
-
# ``w:r``, and docx-studio its break, which it
|
|
1990
|
+
# The run holds only a page or column break, or a picture: python-docx
|
|
1991
|
+
# formats its ``w:r``, and docx-studio its break or picture, which it
|
|
1992
|
+
# tells by the run's identity.
|
|
1908
1993
|
run_sync(
|
|
1909
1994
|
self._session.doc.format.apply(
|
|
1910
1995
|
{
|
|
@@ -1915,7 +2000,7 @@ class Run:
|
|
|
1915
2000
|
},
|
|
1916
2001
|
),
|
|
1917
2002
|
)
|
|
1918
|
-
# Its break holds the formatting now, which what it takes next continues.
|
|
2003
|
+
# Its break or picture holds the formatting now, which what it takes next continues.
|
|
1919
2004
|
self._fresh = False
|
|
1920
2005
|
return
|
|
1921
2006
|
if self._is_collapsed_range:
|
|
@@ -2125,6 +2210,22 @@ class Run:
|
|
|
2125
2210
|
return Font(self)
|
|
2126
2211
|
|
|
2127
2212
|
|
|
2213
|
+
class _Text:
|
|
2214
|
+
"""Proxy object wrapping ``<w:t>`` element: what ``Run.add_text``
|
|
2215
|
+
returns, as python-docx returns one for the ``w:t`` it adds. It has no
|
|
2216
|
+
public API; its element (``_t``) is not available here."""
|
|
2217
|
+
|
|
2218
|
+
def __init__(self, run: "Run") -> None:
|
|
2219
|
+
super().__init__()
|
|
2220
|
+
self._run = run
|
|
2221
|
+
|
|
2222
|
+
def __getattr__(self, name: str) -> Any:
|
|
2223
|
+
from docx.oxml import guard_xml_attr
|
|
2224
|
+
|
|
2225
|
+
guard_xml_attr("_Text", name)
|
|
2226
|
+
raise AttributeError(f"'_Text' object has no attribute {name!r}")
|
|
2227
|
+
|
|
2228
|
+
|
|
2128
2229
|
class Font(ElementProxyEquality):
|
|
2129
2230
|
"""Font properties of a Run. Accessed via `run.font`; do not instantiate."""
|
|
2130
2231
|
|