athena-python-docx 0.19.0__tar.gz → 0.21.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.19.0 → athena_python_docx-0.21.0}/CLAUDE.md +115 -33
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/DOCX_EXEC_LAB.md +4 -4
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/PKG-INFO +8 -9
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/README.md +6 -7
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/__init__.py +1 -1
- athena_python_docx-0.21.0/docx/_citations.py +74 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_http.py +122 -91
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_image_utils.py +160 -1
- athena_python_docx-0.21.0/docx/_references.py +91 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/api.py +6 -6
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/client.py +1 -8
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/commands.py +35 -50
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/comments.py +6 -2
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/document.py +141 -59
- athena_python_docx-0.21.0/docx/enum/shape.py +30 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/style.py +17 -68
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/errors.py +3 -3
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/opc/coreprops.py +45 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/section.py +75 -33
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/shape.py +23 -6
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/shared.py +10 -8
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/styles.py +88 -33
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/table.py +88 -108
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/hyperlink.py +13 -11
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/paragraph.py +46 -78
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/parfmt.py +25 -22
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/run.py +50 -11
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/pyproject.toml +6 -11
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab.py +1 -1
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/round_trip_smoke.py +6 -7
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/smoke_test_block_not_found.py +2 -11
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/validate_find_replace_asset.py +1 -1
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/METHODOLOGY.md +9 -9
- athena_python_docx-0.21.0/tests/fidelity/README.md +50 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/fake_session.py +32 -33
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/README.md +1 -1
- athena_python_docx-0.21.0/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +3 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/intentional_deviations.json +2 -2
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/reports/GAP_ANALYSIS.md +5 -33
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/reports/gap_report.json +9 -1688
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/snapshots/athena_latest.json +2812 -580
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_athena_extensions_registry.py +4 -2
- athena_python_docx-0.21.0/tests/test_citations.py +151 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_commands.py +4 -3
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_create.py +5 -11
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_create_from_template.py +167 -52
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_factory_validation.py +2 -2
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_docx_exec_lab.py +1 -1
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_parity_misc.py +35 -6
- athena_python_docx-0.21.0/tests/test_python_docx_api_parity.py +357 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_hyperlink.py +6 -4
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_parfmt.py +37 -17
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_dimensions.py +36 -17
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_smoke_integration.py +4 -5
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/uv.lock +1 -1
- athena_python_docx-0.19.0/docx/_references.py +0 -82
- athena_python_docx-0.19.0/tests/fidelity/README.md +0 -71
- athena_python_docx-0.19.0/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -1
- athena_python_docx-0.19.0/tests/fidelity/runner.py +0 -486
- athena_python_docx-0.19.0/tests/test_python_docx_api_parity.py +0 -161
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/.gitignore +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_batching.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_buffer.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_execution.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_postproc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_ptc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/_timeouts.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/charts.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/section.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/table.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/enum/text.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/exceptions.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/fields.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/footnotes.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/math.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/oxml/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/revisions.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/sdt.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/session.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/settings.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/styles/style.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/font.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/toc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/docx/typing.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_examples/fast_table_fill.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_examples/find_replace_literal.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/dump_wire_fixtures.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/publish.sh +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/scripts/release.sh +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/conftest.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/README.md +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_add_section_extract_items.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_add_table_not_supported.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_add_hyperlink_stash.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_add_run_via_cell_insert.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_format_stash.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_run_format_stash.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_inner_run_guard.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_cell_text_replace_semantics.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_comments.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_document_clear.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_docx_exec_lab_server.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_execution_scope.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_find_replace_session_open.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_image_url_data_uri.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_oxml_shim.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_positional_cell_id.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_cell_format_rewrite.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_cell_run_format_rewrite.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_postproc_ref_restore.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_validate_find_replace_asset_script.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_xml_attr_guard.py +0 -0
- {athena_python_docx-0.19.0 → athena_python_docx-0.21.0}/tests/test_zod_wire_contract.py +0 -0
|
@@ -67,11 +67,7 @@ These standard python-docx members don't apply to a Superdoc-backed SDK:
|
|
|
67
67
|
### Phase-3b upstream-blocked surface
|
|
68
68
|
|
|
69
69
|
These are *shipped at the surface* but partially or fully no-op at
|
|
70
|
-
runtime, pending
|
|
71
|
-
upstream constraints have been verified against
|
|
72
|
-
[SuperDoc's published docs](https://docs.superdoc.dev/document-api/reference/styles/apply)
|
|
73
|
-
and the bundled TypeScript types in
|
|
74
|
-
`node_modules/@superdoc-dev/sdk/dist/generated/client.d.ts`. See
|
|
70
|
+
runtime, pending DOCX Studio backend changes. See
|
|
75
71
|
`docx-studio/PYTHON_DOCX_PARITY_GAPS.md` § *What unblocks the
|
|
76
72
|
remaining work* for the exact wire-op shape needed to unblock each.
|
|
77
73
|
|
|
@@ -132,16 +128,15 @@ not file-backed. Each is documented in the relevant docstring.
|
|
|
132
128
|
|
|
133
129
|
- **`Document.create(name=, base_url=, api_key=, parent_folder_id=, workspace_id=, docx=, agora_base_url=)`**
|
|
134
130
|
classmethod. Stock python-docx returns a blank in-memory document
|
|
135
|
-
for `Document(None)`; we can't fabricate a
|
|
131
|
+
for `Document(None)`; we can't fabricate a Word document asset
|
|
136
132
|
client-side, so net-new asset creation is a separate factory that
|
|
137
133
|
hits `POST {base_url}/docs/empty`. The constructor positional-arg
|
|
138
134
|
shape (`Document(asset_id)`) is preserved for parity.
|
|
139
135
|
- **`docx=path`** mirrors the upstream `Document(docx="template.docx")`
|
|
140
|
-
constructor kwarg: when provided, the
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
default Athena template is applied as today.
|
|
136
|
+
constructor kwarg: when provided, the SDK creates a normal Word
|
|
137
|
+
document asset through Agora's docx-studio bridge, then imports the
|
|
138
|
+
local `.docx` into that asset. Without `docx=`, the default Athena
|
|
139
|
+
template is applied as today.
|
|
145
140
|
- **`agora_base_url=`** is a transport-detail kwarg only required when
|
|
146
141
|
the SDK can't derive the agora host from `base_url` (or from
|
|
147
142
|
`$ATHENA_AGORA_BASE_URL`). The default substitution rule replaces
|
|
@@ -222,22 +217,6 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
222
217
|
the same `Hyperlink` class the read path already exposes. Also
|
|
223
218
|
available as `Run.add_hyperlink` for convenience.
|
|
224
219
|
|
|
225
|
-
- **`Paragraph.add_citation(*, source, text=None, anchor=None,
|
|
226
|
-
display_value=None, label=None) -> str`** + **`Document.remove_citation
|
|
227
|
-
(*, citation_id, soft=True)`** — source-citation markers (Athena
|
|
228
|
-
studio-linking; no python-docx analog, `issue=None`). Attaches a
|
|
229
|
-
Word-style superscript citation marker pointing at an Athena asset
|
|
230
|
-
(`source`, an `AssetReference`), optionally narrowed by `anchor` (a
|
|
231
|
-
sheet range, PDF page, …). Renders in Olympus as a clickable superscript
|
|
232
|
-
with a hover preview + Citations-panel entry — the same unified
|
|
233
|
-
citation system as sheets / PPTX / native docs; clicking opens the
|
|
234
|
-
source in a new tab. Routes through `CreateCitation` / `RemoveCitation`;
|
|
235
|
-
the studio server derives the openable `citation_string` from
|
|
236
|
-
`source_ref` + `source_anchor` via `@athenaintel/references` (single
|
|
237
|
-
canonical serializer). `docx/_references.py` mirrors the pptx
|
|
238
|
-
`AssetReference` + anchor re-exports off the shared `athena-references`
|
|
239
|
-
package.
|
|
240
|
-
|
|
241
220
|
- **`Run.add_field(kind, *, args=None, cached_result=None) -> Field`**
|
|
242
221
|
+ **`Document.fields: Fields`** — generic Word field insertion.
|
|
243
222
|
Supports `"PAGE"`, `"NUMPAGES"`, `"DATE"`, `"TIME"`, `"AUTHOR"`,
|
|
@@ -405,6 +384,38 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
405
384
|
cleanup loops, which left horizontal-rule and scratch-content artifacts
|
|
406
385
|
in the document during failed-run recoveries.
|
|
407
386
|
|
|
387
|
+
- **`Paragraph.add_citation(source, *, anchor=None, excerpt=None,
|
|
388
|
+
display_value=None) -> str`** + **`Paragraph.clear_citations()`** +
|
|
389
|
+
**`Document.add_citation(source, *, destination_anchor, anchor=None,
|
|
390
|
+
...)`** + **`Document.remove_citation(citation_id)`** (0.20.0+) —
|
|
391
|
+
SDK-native Athena citations. This is the programmatic equivalent of
|
|
392
|
+
the user selecting DOCX text and choosing "Use selection as citation
|
|
393
|
+
destination/source" in Olympus: it writes the canonical document
|
|
394
|
+
citation record into the document's ``citations`` Y.Array and applies
|
|
395
|
+
the citation-blue highlight to the destination paragraph/range. It is
|
|
396
|
+
not a live link and does not overwrite destination text.
|
|
397
|
+
|
|
398
|
+
Common agent pattern after writing a supported claim:
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from docx import Document
|
|
402
|
+
from docx._references import AssetReference, SheetRangeAnchor
|
|
403
|
+
|
|
404
|
+
doc = Document("asset_word")
|
|
405
|
+
p = doc.add_paragraph("The combined assessment identified 20,049 total vulnerabilities.")
|
|
406
|
+
citation_id = p.add_citation(
|
|
407
|
+
AssetReference(id="asset_spreadsheet"),
|
|
408
|
+
anchor=SheetRangeAnchor(sheet_id=0, range="B2:B8"),
|
|
409
|
+
excerpt="20,049 total vulnerabilities",
|
|
410
|
+
display_value="Vulnerability total",
|
|
411
|
+
)
|
|
412
|
+
doc.save()
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Use ``Document.add_citation(..., destination_anchor=PmNodeAnchor(...))``
|
|
416
|
+
only when you already have a DOCX editor anchor id. For normal writing,
|
|
417
|
+
cite the ``Paragraph`` proxy you just created or found.
|
|
418
|
+
|
|
408
419
|
- **`Document.export_docx(path=None, *, include_revisions=False)
|
|
409
420
|
-> bytes`** (0.11.4+) — export the document's current state as
|
|
410
421
|
``.docx`` bytes, optionally writing to ``path``. Closes the gap
|
|
@@ -413,16 +424,13 @@ Issue numbers reference `python-openxml/python-docx`.
|
|
|
413
424
|
harnesses and CI workflows need a programmatic .docx export to
|
|
414
425
|
diff against ``python-docx`` output that doesn't require a
|
|
415
426
|
human-driven Olympus UI action. Routes through ``ExportDocx`` →
|
|
416
|
-
apps/api
|
|
417
|
-
recommended backend export path per the SuperDoc team — Document
|
|
418
|
-
API, not the browser-side ``editor.exportDocx`` shim). apps/api
|
|
427
|
+
apps/api's backend export path. apps/api
|
|
419
428
|
writes the session state to a temp ``.docx``, reads bytes back,
|
|
420
429
|
base64-encodes for the wire, and unlinks the temp in a
|
|
421
430
|
``finally`` block. The SDK decodes and writes to ``path``.
|
|
422
431
|
``include_revisions=True`` raises ``DocxError`` pre-flight:
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
through ``doc.save({out})``.
|
|
432
|
+
the current backend export path has no ``includeRevisions`` support,
|
|
433
|
+
so honoring the flag isn't possible yet.
|
|
426
434
|
|
|
427
435
|
Template seeding: ``Document.create()`` (no ``docx=``) already
|
|
428
436
|
produces an exportable asset because ``POST /docs/empty`` seeds
|
|
@@ -617,6 +625,80 @@ natively, the SDK should swap to the upstream signature in place;
|
|
|
617
625
|
this section is the canonical reference for what each Athena
|
|
618
626
|
extension wires up.
|
|
619
627
|
|
|
628
|
+
### Behavioral-parity deviations (2026 deep-dive, v0.19.0)
|
|
629
|
+
|
|
630
|
+
A deep behavioral audit against python-docx 1.2.0 (the structural
|
|
631
|
+
parity ratchet only sees shape, not runtime behavior) fixed ~40
|
|
632
|
+
divergences so they now match upstream exactly — `Pt`/`RGBColor`
|
|
633
|
+
coercion, `Font.size` bare-int-is-EMU, `Font.underline`
|
|
634
|
+
SINGLE→`True`/NONE→`False`, `line_spacing` integer multipliers,
|
|
635
|
+
`line_spacing_rule` rule-only members, `Hyperlink.url`/`.address`,
|
|
636
|
+
`Table.autofit`/`_Row.cells`/`_Column.cells`, `Section`
|
|
637
|
+
orientation/start-type defaults + `Sections` slicing,
|
|
638
|
+
`Styles.get_by_id`/`get_style_id`/`default(LIST)`/`add_style`,
|
|
639
|
+
`Document.add_heading` (`ValueError`), `add_paragraph` strict heading
|
|
640
|
+
routing, `add_picture` native size + aspect ratio, `WD_BUILTIN_STYLE`
|
|
641
|
+
(now the 132-member int enum aliased to `WD_STYLE`),
|
|
642
|
+
`docx.enum.shape.WD_INLINE_SHAPE`, `InlineShape.type`/zero-dimensions,
|
|
643
|
+
and `CoreProperties` validation. These are not deviations — they close
|
|
644
|
+
gaps. The items below are the **residual intentional deviations** that
|
|
645
|
+
remain because matching upstream would break the asset-backed/HTTP
|
|
646
|
+
architecture or a SuperDoc constraint:
|
|
647
|
+
|
|
648
|
+
- **`WD_*` enum `.value` is the SuperDoc wire string, not the MS Word
|
|
649
|
+
integer constant.** `WD_ALIGN_PARAGRAPH.CENTER.value == "center"`
|
|
650
|
+
(upstream: `1`); `int(member)` / `member == 1` / `WD_*(1)` therefore
|
|
651
|
+
differ. The string value is load-bearing — every command serializes
|
|
652
|
+
`enum.value` directly onto the wire (`underline=value.value`,
|
|
653
|
+
`WD_COLOR_INDEX(v).value`, …), so int-valuing the enums would require
|
|
654
|
+
re-plumbing the entire command layer. Members are accessed by name
|
|
655
|
+
(`WD_ALIGN_PARAGRAPH.CENTER`), so the drift is academic for normal
|
|
656
|
+
use. (`WD_STYLE`/`WD_BUILTIN_STYLE` and `WD_INLINE_SHAPE_TYPE` are NOT
|
|
657
|
+
wire-load-bearing and DO carry the upstream int values.)
|
|
658
|
+
|
|
659
|
+
- **`RGBColor.from_string` additionally accepts a leading `#`.** Upstream
|
|
660
|
+
rejects `"#FF0000"`; agents routinely pass it, so a single `#` is
|
|
661
|
+
stripped before the (otherwise byte-identical) upstream slice parse.
|
|
662
|
+
A strict superset — every value upstream accepts parses identically.
|
|
663
|
+
|
|
664
|
+
- **`_Cell.vertical_alignment` setter accepts the four SuperDoc wire
|
|
665
|
+
tokens** (`"top"`/`"center"`/`"bottom"`/`"both"`) in addition to
|
|
666
|
+
`WD_ALIGN_VERTICAL` members. Upstream rejects all plain strings; this
|
|
667
|
+
is an ergonomic superset (typos like `"middle"` still raise
|
|
668
|
+
`ValueError`).
|
|
669
|
+
|
|
670
|
+
- **`Table.cell(row, col)` bounds-checks each axis independently** and
|
|
671
|
+
raises `IndexError` for an out-of-range row or column. Upstream
|
|
672
|
+
indexes a single flat row-major `_cells` list, so a column overflow
|
|
673
|
+
spills into the next row and `cell(-1, -1)` resolves against the flat
|
|
674
|
+
list (NOT the bottom-right cell). Athena's per-axis contract is the
|
|
675
|
+
more intuitive, stricter behavior for an HTTP-backed proxy that can't
|
|
676
|
+
cheaply enumerate every cell. `(0,0)` and in-range negative indices
|
|
677
|
+
behave identically to upstream.
|
|
678
|
+
|
|
679
|
+
- **`BaseStyle.style_id` returns the display name for built-ins** (so
|
|
680
|
+
`style_id == name`). The SDK is HTTP-only and can't read `styles.xml`
|
|
681
|
+
to recover the OOXML styleId (`"Heading 1"` → `"Heading1"`); the wire
|
|
682
|
+
format also uses the display name as the style id. Consequently
|
|
683
|
+
`get_by_id("Heading1", …)` / `"Heading1" in styles` won't resolve the
|
|
684
|
+
OOXML-id form (use the display name).
|
|
685
|
+
|
|
686
|
+
- **`Document.add_table(rows, cols)` requires `rows >= 1` and
|
|
687
|
+
`cols >= 1`.** Upstream allows a 0-row/0-col grid you later populate,
|
|
688
|
+
but SuperDoc's ProseMirror table node can't represent one; the SDK
|
|
689
|
+
raises eagerly rather than failing opaquely on the wire.
|
|
690
|
+
|
|
691
|
+
- **`Comment.comment_id` returns `str`, not `int`.** SuperDoc uses
|
|
692
|
+
non-numeric entity ids (`"c-42"`), so the upstream `int` contract
|
|
693
|
+
can't be honored. Tracked in `SUPERDOC_UPSTREAM_REQUESTS.md`.
|
|
694
|
+
|
|
695
|
+
- **`Section` dimension setters and `ParagraphFormat.line_spacing_rule
|
|
696
|
+
= None` warn-and-preserve on a clear** rather than raising (upstream
|
|
697
|
+
accepts `None` to clear, but SuperDoc's merging mutation ops have no
|
|
698
|
+
single-attribute clear). They emit a `Pending…ClearWarning` and leave
|
|
699
|
+
the value intact instead of destructively clearing the whole block.
|
|
700
|
+
Tracked in `SUPERDOC_UPSTREAM_REQUESTS.md`.
|
|
701
|
+
|
|
620
702
|
### If you need a deviation
|
|
621
703
|
|
|
622
704
|
If there is a genuine technical reason why a deviation from python-docx is necessary:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# DocX Execution Lab
|
|
2
2
|
|
|
3
3
|
`scripts/docx_exec_lab.py` is a headless runner for quickly testing
|
|
4
|
-
`athena-python-docx` snippets against Athena
|
|
4
|
+
`athena-python-docx` snippets against Athena Word document assets. It
|
|
5
5
|
shortens the debug loop by running local SDK code directly against a
|
|
6
6
|
chosen DOCX Studio API, capturing stdout/stderr/errors/timings, and
|
|
7
7
|
optionally exporting the result to `.docx` for assertions.
|
|
@@ -85,10 +85,10 @@ uv run python scripts/docx_exec_lab.py \
|
|
|
85
85
|
--export-docx
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
## Local UI With
|
|
88
|
+
## Local UI With DOCX Editor Embed
|
|
89
89
|
|
|
90
90
|
The lab also includes a local-only HTML UI that wraps the same headless
|
|
91
|
-
runner and iframes Olympus's existing
|
|
91
|
+
runner and iframes Olympus's existing DOCX editor embed route.
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
94
|
cd docx-studio/python-sdk
|
|
@@ -107,7 +107,7 @@ Defaults:
|
|
|
107
107
|
The UI accepts an `asset_id`, Python code, and optional assertions. The
|
|
108
108
|
right pane can mint an editable embed token through staging Agora and
|
|
109
109
|
iframe the returned `https://staging-app.athenaintel.com/embed/{token}`
|
|
110
|
-
URL, so changes render in the real Olympus
|
|
110
|
+
URL, so changes render in the real Olympus DOCX editor viewer.
|
|
111
111
|
|
|
112
112
|
If the staging Agora URL differs, pass:
|
|
113
113
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Drop-in replacement for python-docx that connects to Athena's
|
|
3
|
+
Version: 0.21.0
|
|
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>
|
|
7
7
|
License-Expression: MIT
|
|
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
# athena-python-docx
|
|
30
30
|
|
|
31
|
-
Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's
|
|
31
|
+
Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Keryx-backed Word document stack.
|
|
32
32
|
|
|
33
33
|
## Quick start
|
|
34
34
|
|
|
@@ -36,7 +36,7 @@ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that
|
|
|
36
36
|
from docx import Document
|
|
37
37
|
from docx.shared import Inches, Pt, RGBColor
|
|
38
38
|
|
|
39
|
-
# Open an existing
|
|
39
|
+
# Open an existing Word document asset by its Athena asset_id
|
|
40
40
|
with Document("asset_abc123") as doc:
|
|
41
41
|
doc.add_heading("Market Analysis", level=1)
|
|
42
42
|
|
|
@@ -75,15 +75,14 @@ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
|
|
|
75
75
|
Python snippet with this checkout of `athena-python-docx`, captures
|
|
76
76
|
stdout/stderr/errors/timings, and can export the resulting `.docx` for
|
|
77
77
|
text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
|
|
78
|
-
an Olympus
|
|
78
|
+
an Olympus Word document embed preview pane. See `DOCX_EXEC_LAB.md`.
|
|
79
79
|
|
|
80
80
|
## Environment variables
|
|
81
81
|
|
|
82
|
-
Required when connecting to
|
|
82
|
+
Required when connecting to DOCX Studio (set by Athena backend when executing in Daytona):
|
|
83
83
|
|
|
84
|
-
- `
|
|
85
|
-
- `
|
|
86
|
-
- `ATHENA_WORKSPACE_ID` — workspace routing segment
|
|
84
|
+
- `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
|
|
85
|
+
- `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
|
|
87
86
|
|
|
88
87
|
## License
|
|
89
88
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# athena-python-docx
|
|
2
2
|
|
|
3
|
-
Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's
|
|
3
|
+
Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that connects to Athena's Keryx-backed Word document stack.
|
|
4
4
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ Drop-in replacement for [python-docx](https://python-docx.readthedocs.io/) that
|
|
|
8
8
|
from docx import Document
|
|
9
9
|
from docx.shared import Inches, Pt, RGBColor
|
|
10
10
|
|
|
11
|
-
# Open an existing
|
|
11
|
+
# Open an existing Word document asset by its Athena asset_id
|
|
12
12
|
with Document("asset_abc123") as doc:
|
|
13
13
|
doc.add_heading("Market Analysis", level=1)
|
|
14
14
|
|
|
@@ -47,15 +47,14 @@ headless runner in `scripts/docx_exec_lab.py`. It executes an arbitrary
|
|
|
47
47
|
Python snippet with this checkout of `athena-python-docx`, captures
|
|
48
48
|
stdout/stderr/errors/timings, and can export the resulting `.docx` for
|
|
49
49
|
text assertions. `scripts/docx_exec_lab_server.py` adds a local UI with
|
|
50
|
-
an Olympus
|
|
50
|
+
an Olympus Word document embed preview pane. See `DOCX_EXEC_LAB.md`.
|
|
51
51
|
|
|
52
52
|
## Environment variables
|
|
53
53
|
|
|
54
|
-
Required when connecting to
|
|
54
|
+
Required when connecting to DOCX Studio (set by Athena backend when executing in Daytona):
|
|
55
55
|
|
|
56
|
-
- `
|
|
57
|
-
- `
|
|
58
|
-
- `ATHENA_WORKSPACE_ID` — workspace routing segment
|
|
56
|
+
- `ATHENA_DOCX_BASE_URL` — DOCX Studio API base URL
|
|
57
|
+
- `ATHENA_DOCX_API_KEY` — Athena API key or service-issued DOCX Studio token
|
|
59
58
|
|
|
60
59
|
## License
|
|
61
60
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Helpers for SDK-native Athena citations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from docx._references import AssetReference
|
|
9
|
+
from docx.commands import AddCitation
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def new_citation_id() -> str:
|
|
13
|
+
return f"citation_{uuid.uuid4().hex[:12]}"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def source_ref_to_dict(source: AssetReference) -> dict[str, Any]:
|
|
17
|
+
if not isinstance(source, AssetReference):
|
|
18
|
+
raise TypeError(f"source must be an AssetReference; got {type(source).__name__}")
|
|
19
|
+
return source.to_dict()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def anchor_to_dict(anchor: object | None) -> dict[str, Any] | None:
|
|
23
|
+
if anchor is None:
|
|
24
|
+
return None
|
|
25
|
+
if not hasattr(anchor, "to_dict"):
|
|
26
|
+
raise TypeError(
|
|
27
|
+
"anchor must be an Anchor dataclass (SheetRangeAnchor, "
|
|
28
|
+
f"PmNodeAnchor, etc.) — got {type(anchor).__name__}"
|
|
29
|
+
)
|
|
30
|
+
value = anchor.to_dict()
|
|
31
|
+
if not isinstance(value, dict) or not value.get("type"):
|
|
32
|
+
raise TypeError("anchor.to_dict() must return a dict with a 'type' field")
|
|
33
|
+
return value
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def destination_anchor_to_dict(destination_anchor: object) -> dict[str, Any]:
|
|
37
|
+
if hasattr(destination_anchor, "to_dict"):
|
|
38
|
+
destination_anchor = destination_anchor.to_dict()
|
|
39
|
+
if not isinstance(destination_anchor, dict):
|
|
40
|
+
raise TypeError(
|
|
41
|
+
"destination_anchor must be a PmNodeAnchor, PmNodeRangeAnchor, or wire dict"
|
|
42
|
+
)
|
|
43
|
+
anchor_type = destination_anchor.get("type")
|
|
44
|
+
if anchor_type == "pm_node" and destination_anchor.get("nodeId"):
|
|
45
|
+
return dict(destination_anchor)
|
|
46
|
+
if (
|
|
47
|
+
anchor_type == "pm_node_range"
|
|
48
|
+
and destination_anchor.get("startNodeId")
|
|
49
|
+
and destination_anchor.get("endNodeId")
|
|
50
|
+
):
|
|
51
|
+
return dict(destination_anchor)
|
|
52
|
+
raise ValueError(
|
|
53
|
+
"destination_anchor must be {'type':'pm_node','nodeId':...} or "
|
|
54
|
+
"{'type':'pm_node_range','startNodeId':...,'endNodeId':...}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def build_add_citation_command(
|
|
59
|
+
*,
|
|
60
|
+
destination_anchor: object,
|
|
61
|
+
source: AssetReference,
|
|
62
|
+
anchor: object | None,
|
|
63
|
+
excerpt: str | None,
|
|
64
|
+
display_value: str | None,
|
|
65
|
+
) -> tuple[str, AddCitation]:
|
|
66
|
+
citation_id = new_citation_id()
|
|
67
|
+
return citation_id, AddCitation(
|
|
68
|
+
destination_anchor=destination_anchor_to_dict(destination_anchor),
|
|
69
|
+
source_ref=source_ref_to_dict(source),
|
|
70
|
+
source_anchor=anchor_to_dict(anchor),
|
|
71
|
+
citation_id=citation_id,
|
|
72
|
+
excerpt=excerpt,
|
|
73
|
+
display_value=display_value,
|
|
74
|
+
)
|