athena-python-docx 0.5.0__tar.gz → 0.5.1__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.5.0 → athena_python_docx-0.5.1}/PKG-INFO +1 -1
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/__init__.py +1 -1
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/pyproject.toml +1 -1
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/scripts/release.sh +8 -8
- athena_python_docx-0.5.1/scripts/round_trip_smoke.py +232 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/.gitignore +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/CLAUDE.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/README.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_batching.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_buffer.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_http.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/api.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/client.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/commands.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/comments.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/document.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/section.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/style.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/table.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/enum/text.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/errors.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/exceptions.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/section.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/settings.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/shape.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/shared.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/style.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/table.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/font.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/paragraph.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/run.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/docx/typing.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/scripts/publish.sh +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/conftest.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/23_nested_table.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/runner.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/README.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_commands.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_comments.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/tests/test_zod_wire_contract.py +0 -0
- {athena_python_docx-0.5.0 → athena_python_docx-0.5.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "athena-python-docx"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.1"
|
|
8
8
|
description = "Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Tag + push a new athena-python-docx release. CI handles the rest:
|
|
3
|
-
# PyPI publish, Docker image rebuild, Daytona snapshot creation,
|
|
4
|
-
# flip in agora dev +
|
|
3
|
+
# PyPI publish, Docker image rebuild, Daytona snapshot creation,
|
|
4
|
+
# Infisical flip in agora dev + staging. See
|
|
5
5
|
# .github/workflows/athena-python-docx-release.yml for the full flow.
|
|
6
6
|
#
|
|
7
7
|
# Usage:
|
|
@@ -65,16 +65,16 @@ cat <<EOF
|
|
|
65
65
|
|
|
66
66
|
Tagged $TAG and pushed. CI is now running the full release pipeline:
|
|
67
67
|
|
|
68
|
-
1. PyPI publish
|
|
68
|
+
1. PyPI publish → https://pypi.org/project/athena-python-docx/$VERSION/
|
|
69
69
|
2. Docker image rebuild → athenaintel/daytona-document:$VERSION
|
|
70
|
-
3. Daytona snapshot
|
|
71
|
-
4.
|
|
70
|
+
3. Daytona snapshot → document-exec:$VERSION
|
|
71
|
+
4. Infisical flip → agora/dev + agora/staging
|
|
72
72
|
|
|
73
73
|
Watch the run:
|
|
74
74
|
https://github.com/Athena-Intel/demo-app-monorepo/actions/workflows/athena-python-docx-release.yml
|
|
75
75
|
|
|
76
|
-
For
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
For prod rollout, after canary verification (run from the repo root with
|
|
77
|
+
the Infisical CLI authed against the agora project):
|
|
78
|
+
infisical secrets set DAYTONA_DOCUMENT_EXEC_SNAPSHOT=document-exec:$VERSION --env=prod
|
|
79
79
|
|
|
80
80
|
EOF
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Round-trip smoke test against a live docx-studio API + SuperDocument asset.
|
|
2
|
+
|
|
3
|
+
Drives a representative scenario through the SDK (mutations + reads)
|
|
4
|
+
and asserts on the read-back shape. Designed to catch the
|
|
5
|
+
``SDK → docx-studio → Keryx → SuperDoc`` class of regression that
|
|
6
|
+
unit tests with FakeSession + the cross-language Zod contract test
|
|
7
|
+
can't see — namely, "the wire format we send is technically valid
|
|
8
|
+
but SuperDoc doesn't apply it the way we expect."
|
|
9
|
+
|
|
10
|
+
Per-PR usage in CI (after ``Deploy DOCX Studio Preview`` succeeds):
|
|
11
|
+
|
|
12
|
+
ASSET_ID=asset_ci_round_trip_test \\
|
|
13
|
+
DOCX_STUDIO_BASE_URL=https://docx-studio-pr19782-preview... \\
|
|
14
|
+
ATHENA_DOCX_API_KEY=$CI_DOCX_TEST_API_KEY \\
|
|
15
|
+
python scripts/round_trip_smoke.py
|
|
16
|
+
|
|
17
|
+
Manual usage (against staging, with a personal API key):
|
|
18
|
+
|
|
19
|
+
ASSET_ID=asset_49b963a4-... \\
|
|
20
|
+
ATHENA_DOCX_API_KEY=$BG_STAGING_API_KEY \\
|
|
21
|
+
python scripts/round_trip_smoke.py
|
|
22
|
+
|
|
23
|
+
Exit codes:
|
|
24
|
+
- 0 — all checks passed
|
|
25
|
+
- 1 — at least one check failed (treat as a real regression)
|
|
26
|
+
- 2 — environment / network unavailability (treat as infra flake;
|
|
27
|
+
callers can soft-fail in CI)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import os
|
|
33
|
+
import sys
|
|
34
|
+
import time
|
|
35
|
+
import traceback
|
|
36
|
+
from dataclasses import dataclass
|
|
37
|
+
from typing import Callable
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _emit(name: str, ok: bool, detail: str = "") -> None:
|
|
41
|
+
glyph = "[ok]" if ok else "[FAIL]"
|
|
42
|
+
line = f"{glyph} {name}"
|
|
43
|
+
if detail:
|
|
44
|
+
line += f" — {detail}"
|
|
45
|
+
print(line, flush=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class CheckResult:
|
|
50
|
+
name: str
|
|
51
|
+
ok: bool
|
|
52
|
+
detail: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def main() -> int:
|
|
56
|
+
asset_id = os.environ.get("ASSET_ID")
|
|
57
|
+
if not asset_id:
|
|
58
|
+
print(
|
|
59
|
+
"ERROR: set ASSET_ID env var to a SuperDocument asset id the "
|
|
60
|
+
"test API key has write access to. Skipping with exit 2 so "
|
|
61
|
+
"callers can soft-fail in CI.",
|
|
62
|
+
file=sys.stderr,
|
|
63
|
+
)
|
|
64
|
+
return 2
|
|
65
|
+
|
|
66
|
+
base_url = os.environ.get("DOCX_STUDIO_BASE_URL")
|
|
67
|
+
api_key = os.environ.get("ATHENA_DOCX_API_KEY")
|
|
68
|
+
if not api_key:
|
|
69
|
+
print(
|
|
70
|
+
"ERROR: ATHENA_DOCX_API_KEY missing. Skipping with exit 2.",
|
|
71
|
+
file=sys.stderr,
|
|
72
|
+
)
|
|
73
|
+
return 2
|
|
74
|
+
|
|
75
|
+
# Insert local SDK first so this script always exercises the
|
|
76
|
+
# just-built code (when run from the repo) rather than whatever
|
|
77
|
+
# version is on the PYTHONPATH.
|
|
78
|
+
sdk_root = os.path.join(
|
|
79
|
+
os.path.dirname(os.path.abspath(__file__)),
|
|
80
|
+
"..",
|
|
81
|
+
)
|
|
82
|
+
sys.path.insert(0, os.path.abspath(sdk_root))
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
from docx import Document
|
|
86
|
+
from docx.errors import DocxError
|
|
87
|
+
except ImportError as e:
|
|
88
|
+
print(f"ERROR: failed to import SDK from {sdk_root}: {e}", file=sys.stderr)
|
|
89
|
+
return 2
|
|
90
|
+
|
|
91
|
+
print(f"[setup] base_url={base_url or '<default>'}")
|
|
92
|
+
print(f"[setup] asset_id={asset_id}")
|
|
93
|
+
print(f"[setup] sdk_root={sdk_root}")
|
|
94
|
+
|
|
95
|
+
# Tag every paragraph with a unique suffix so re-runs against a
|
|
96
|
+
# long-lived asset stay debuggable (we can grep the asset for the
|
|
97
|
+
# token and find the run that wrote it).
|
|
98
|
+
run_token = f"ci-{int(time.time())}"
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
kwargs: dict = {"api_key": api_key}
|
|
102
|
+
if base_url:
|
|
103
|
+
kwargs["base_url"] = base_url
|
|
104
|
+
doc = Document(asset_id, **kwargs)
|
|
105
|
+
except DocxError as e:
|
|
106
|
+
print(f"ERROR: failed to open document: {e}", file=sys.stderr)
|
|
107
|
+
# Network / auth / 502 — caller treats as infra flake.
|
|
108
|
+
return 2
|
|
109
|
+
|
|
110
|
+
results: list[CheckResult] = []
|
|
111
|
+
|
|
112
|
+
def run_check(name: str, fn: Callable[[], None]) -> None:
|
|
113
|
+
try:
|
|
114
|
+
fn()
|
|
115
|
+
results.append(CheckResult(name, True))
|
|
116
|
+
_emit(name, True)
|
|
117
|
+
except AssertionError as e:
|
|
118
|
+
results.append(CheckResult(name, False, str(e)))
|
|
119
|
+
_emit(name, False, str(e))
|
|
120
|
+
except Exception as e: # noqa: BLE001
|
|
121
|
+
results.append(CheckResult(name, False, f"{type(e).__name__}: {e}"))
|
|
122
|
+
_emit(name, False, f"{type(e).__name__}: {e}")
|
|
123
|
+
traceback.print_exc()
|
|
124
|
+
|
|
125
|
+
# -----------------------------------------------------------------
|
|
126
|
+
# Check 1 (Round 3 #2): Document.add_paragraph segments tabs/newlines
|
|
127
|
+
# -----------------------------------------------------------------
|
|
128
|
+
expected_text_1 = f"[{run_token}] hello\tworld\nfoo"
|
|
129
|
+
|
|
130
|
+
def check_paragraph_segments_tabs_and_newlines() -> None:
|
|
131
|
+
p = doc.add_paragraph(expected_text_1)
|
|
132
|
+
# Read-back: paragraph.text must include the tab and newline as
|
|
133
|
+
# \t and \n (Round 2 #1: _extract_text now renders these).
|
|
134
|
+
# Drain any pending writes to make sure SuperDoc has applied
|
|
135
|
+
# them before we read.
|
|
136
|
+
doc.save()
|
|
137
|
+
text_back = p.text
|
|
138
|
+
assert text_back == expected_text_1, (
|
|
139
|
+
f"add_paragraph + paragraph.text round-trip diverged: "
|
|
140
|
+
f"sent {expected_text_1!r}, got {text_back!r}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
run_check(
|
|
144
|
+
"round-3 #2: Document.add_paragraph segments \\t / \\n into inlines",
|
|
145
|
+
check_paragraph_segments_tabs_and_newlines,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# -----------------------------------------------------------------
|
|
149
|
+
# Check 2 (Round 3 #3): Document.add_heading segments tabs/newlines
|
|
150
|
+
# -----------------------------------------------------------------
|
|
151
|
+
expected_heading = f"[{run_token}] heading\twith-tab"
|
|
152
|
+
|
|
153
|
+
def check_heading_segments_tab() -> None:
|
|
154
|
+
h = doc.add_heading(expected_heading, level=2)
|
|
155
|
+
doc.save()
|
|
156
|
+
text_back = h.text
|
|
157
|
+
assert text_back == expected_heading, (
|
|
158
|
+
f"add_heading + paragraph.text round-trip diverged: "
|
|
159
|
+
f"sent {expected_heading!r}, got {text_back!r}"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
run_check(
|
|
163
|
+
"round-3 #3: Document.add_heading segments \\t into inline",
|
|
164
|
+
check_heading_segments_tab,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# -----------------------------------------------------------------
|
|
168
|
+
# Check 3 (Round 1 + Round 2 #1): bold=True applies, paragraph.text
|
|
169
|
+
# ignores the mark, runs[0].text holds the segment
|
|
170
|
+
# -----------------------------------------------------------------
|
|
171
|
+
expected_bold = f"[{run_token}] this is bold"
|
|
172
|
+
|
|
173
|
+
def check_bold_round_trip() -> None:
|
|
174
|
+
p = doc.add_paragraph(expected_bold)
|
|
175
|
+
doc.save()
|
|
176
|
+
runs = list(p.runs)
|
|
177
|
+
assert runs, "add_paragraph produced no runs"
|
|
178
|
+
runs[0].bold = True
|
|
179
|
+
doc.save()
|
|
180
|
+
# Re-fetch and verify bold mark stuck. Live read goes through
|
|
181
|
+
# _read_inline_attr which re-fetches the paragraph node.
|
|
182
|
+
runs2 = list(p.runs)
|
|
183
|
+
assert runs2 and runs2[0].bold is True, (
|
|
184
|
+
f"bold=True did not persist; got runs[0].bold={runs2 and runs2[0].bold}"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
run_check(
|
|
188
|
+
"round-1: Run.bold=True persists via FormatApply",
|
|
189
|
+
check_bold_round_trip,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# -----------------------------------------------------------------
|
|
193
|
+
# Check 4 (Round 2 #1): paragraph.text reads tabs/newlines verbatim
|
|
194
|
+
# — covered by checks 1 + 2 already, but pin the expected sequence
|
|
195
|
+
# -----------------------------------------------------------------
|
|
196
|
+
def check_paragraph_text_renders_control_chars() -> None:
|
|
197
|
+
# Use a dedicated paragraph so we don't depend on read order.
|
|
198
|
+
sentinel = f"[{run_token}] tab=\there\nbreak=line"
|
|
199
|
+
p = doc.add_paragraph(sentinel)
|
|
200
|
+
doc.save()
|
|
201
|
+
assert p.text == sentinel, (
|
|
202
|
+
f"paragraph.text dropped control chars: {p.text!r} vs {sentinel!r}"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
run_check(
|
|
206
|
+
"round-2 #1: paragraph.text renders \\t and \\n verbatim",
|
|
207
|
+
check_paragraph_text_renders_control_chars,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# -----------------------------------------------------------------
|
|
211
|
+
# Summary
|
|
212
|
+
# -----------------------------------------------------------------
|
|
213
|
+
failed = [r for r in results if not r.ok]
|
|
214
|
+
print()
|
|
215
|
+
print(f"=== Summary: {len(results) - len(failed)}/{len(results)} passed ===")
|
|
216
|
+
for r in failed:
|
|
217
|
+
print(f" [FAIL] {r.name} — {r.detail}")
|
|
218
|
+
if failed:
|
|
219
|
+
return 1
|
|
220
|
+
print("All round-trip checks passed.")
|
|
221
|
+
return 0
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
if __name__ == "__main__":
|
|
225
|
+
try:
|
|
226
|
+
rc = main()
|
|
227
|
+
except KeyboardInterrupt:
|
|
228
|
+
rc = 130
|
|
229
|
+
except Exception:
|
|
230
|
+
traceback.print_exc()
|
|
231
|
+
rc = 1
|
|
232
|
+
raise SystemExit(rc)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|