athena-python-docx 0.11.1__tar.gz → 0.11.3__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.11.1 → athena_python_docx-0.11.3}/CLAUDE.md +12 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/PKG-INFO +1 -1
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/__init__.py +1 -1
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/errors.py +22 -0
- athena_python_docx-0.11.3/docx/oxml/__init__.py +216 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/table.py +32 -25
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/pyproject.toml +1 -1
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/complex_cases.py +15 -37
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/extreme_cases.py +3 -12
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/real_world_cases.py +4 -13
- athena_python_docx-0.11.3/tests/test_cell_add_table_not_supported.py +79 -0
- athena_python_docx-0.11.3/tests/test_oxml_shim.py +174 -0
- athena_python_docx-0.11.1/docx/oxml/__init__.py +0 -148
- athena_python_docx-0.11.1/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -14
- athena_python_docx-0.11.1/tests/fidelity/op_snapshots/23_nested_table.json +0 -9
- athena_python_docx-0.11.1/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -14
- athena_python_docx-0.11.1/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -24
- athena_python_docx-0.11.1/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -10
- athena_python_docx-0.11.1/tests/test_oxml_shim.py +0 -123
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/.gitignore +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/README.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_athena_extension.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_batching.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_buffer.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_http.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_ptc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/_table_styles.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/api.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/bookmarks.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/charts.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/client.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/commands.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/comments.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/document.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/enum/section.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/enum/style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/enum/table.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/enum/text.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/exceptions.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/fields.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/footnotes.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/math.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/revisions.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/sdt.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/section.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/settings.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/shape.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/shared.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/styles/style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/font.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/paragraph.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/parfmt.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/run.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/text/tabstops.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/toc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/docx/typing.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/scripts/publish.sh +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/scripts/release.sh +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/scripts/smoke_test_block_not_found.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/conftest.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/README.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/_runner.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/extractor.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/test_pw_corpus.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/firm_templates/test_pw_research_digest.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/03_runs_with_formatting.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/35_full_report.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/54_empty_everything.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/55_single_character_runs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/68_invoice.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/69_newsletter.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/runner.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/fidelity/test_e2e_against_staging.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/README.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/introspect.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/reports/GAP_ANALYSIS.md +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/reports/gap_report.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/snapshots/athena_latest.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_athena_extensions_contract.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_athena_extensions_registry.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_block_not_found_error.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_cell_add_paragraph_wire_shape.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_cell_text_plain_fastpath.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_collapsed_range_format.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_commands.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_comments.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_document_asset_id_property.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_document_create_from_template.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_document_factory_validation.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_e2e_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_hyperlink_coalescing.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_insert_deferred.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_list_styles.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_merged_cell_secondary_slot.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_paragraph_text_len_cache.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_partial_failure_cascade.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_add_paragraph_style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_add_run.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_cell_add_paragraph.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_comments_add_comment.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_enum_section.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_inline_shape.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_insert_paragraph_before.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_paragraph_strict.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_paragraph_style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_paragraph_style_strict.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_parfmt.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_row_col_cell.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_add_break.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_style_strict.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_text.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_run_underline.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_section_dimensions.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_section_onoff.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_silent_stub_table_layout.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_table_set_cell_perf.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_table_style_id_resolution.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_temporarily_unavailable.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/tests/test_zod_wire_contract.py +0 -0
- {athena_python_docx-0.11.1 → athena_python_docx-0.11.3}/uv.lock +0 -0
|
@@ -39,6 +39,18 @@ These standard python-docx members don't apply to a Superdoc-backed SDK:
|
|
|
39
39
|
`Comment.tables` — SuperDoc models a comment as a single text body,
|
|
40
40
|
not a `BlockItemContainer`. Use `Comment.text` instead. The
|
|
41
41
|
paragraph/table-bearing surface raises `CommentsNotImplementedError`.
|
|
42
|
+
- **`_Cell.add_table(rows, cols)`** — surface preserved for parity
|
|
43
|
+
(signature matches python-docx, no `width` kwarg) but raises
|
|
44
|
+
:class:`docx.errors.NestedTableNotSupportedError` (subclass of
|
|
45
|
+
`NotImplementedError`) at runtime since 0.11.2. SuperDoc 1.8.1 has
|
|
46
|
+
no anchor or content-fragment shape that places a new table inside
|
|
47
|
+
an existing `tableCell` — `create.table` rejects cell-inner
|
|
48
|
+
paragraph anchors with `INVALID_TARGET`, and the `doc.insert`
|
|
49
|
+
workaround used by `_Cell.add_paragraph` doesn't generalize
|
|
50
|
+
because the apps/api `Insert` schema doesn't yet forward
|
|
51
|
+
`nestingPolicy: {tables: "allow"}` and the SuperDoc table-content
|
|
52
|
+
fragment shape isn't documented. Tracked at
|
|
53
|
+
`docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md` § 13.
|
|
42
54
|
- **`docx.oxml.*`** — the entire raw-OOXML module tree (``ns.qn``,
|
|
43
55
|
``OxmlElement``, ``CT_*`` classes, etc.) is unavailable because the
|
|
44
56
|
SDK is HTTP-only against a SuperDoc Y.Doc; there is no local lxml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.3
|
|
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>
|
|
@@ -128,6 +128,28 @@ class LocalSaveTargetNotSupportedError(DocxError, NotImplementedError):
|
|
|
128
128
|
"""
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
class NestedTableNotSupportedError(DocxError, NotImplementedError):
|
|
132
|
+
"""Raised when ``_Cell.add_table(...)`` is called.
|
|
133
|
+
|
|
134
|
+
SuperDoc 1.8.1 cannot place a new top-level block inside an
|
|
135
|
+
existing ``tableCell`` — ``create.table`` rejects a cell-inner
|
|
136
|
+
paragraph anchor with ``INVALID_TARGET - Expected paragraph:<id>
|
|
137
|
+
but found tableCell:<id>``, and there is no ``create.table``
|
|
138
|
+
anchor shape ("inside this cell") that addresses cell content
|
|
139
|
+
directly. The ``doc.insert``-based workaround used by
|
|
140
|
+
``_Cell.text`` / ``_Cell.add_paragraph`` requires a
|
|
141
|
+
``nestingPolicy: {tables: "allow"}`` flag and a table content
|
|
142
|
+
fragment that aren't yet plumbed through the docx-studio command
|
|
143
|
+
bus, so this entire method is unsupported until upstream
|
|
144
|
+
SuperDoc lands the cell-inner addressing fix tracked in
|
|
145
|
+
``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md`` § 13.
|
|
146
|
+
|
|
147
|
+
Subclasses :class:`NotImplementedError` so a generic
|
|
148
|
+
``except NotImplementedError`` catches it without importing the
|
|
149
|
+
typed class.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
|
|
131
153
|
class ValidationError(DocxError):
|
|
132
154
|
"""Raised when SDK-level validation fails (bad args, out-of-range indices)."""
|
|
133
155
|
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Stub package — ``docx.oxml`` is intentionally unavailable in
|
|
2
|
+
athena-python-docx.
|
|
3
|
+
|
|
4
|
+
python-docx upstream exposes raw OOXML element classes (``OxmlElement``,
|
|
5
|
+
``CT_*``, ``qn``, ``nsmap``, …) for advanced users who manipulate
|
|
6
|
+
Word's XML directly. athena-python-docx is backed by a SuperDoc Y.Doc
|
|
7
|
+
+ Keryx pipeline, not a local OOXML tree, so there is no XML element
|
|
8
|
+
to manipulate.
|
|
9
|
+
|
|
10
|
+
Before 0.8.0 attempts to ``from docx.oxml.ns import qn`` failed with
|
|
11
|
+
the stdlib's generic ``ModuleNotFoundError: No module named
|
|
12
|
+
'docx.oxml'`` — agent code had to discover the gap by retry. 0.8.0
|
|
13
|
+
turned this package into a typed stub, but the stub raised
|
|
14
|
+
``OxmlNotAvailableError`` on attribute access — which is what
|
|
15
|
+
``from docx.oxml.ns import qn`` triggers, so the import statement
|
|
16
|
+
itself crashed before any line of the agent's actual logic ran. Common
|
|
17
|
+
python-docx convention is to declare ``qn`` / ``OxmlElement`` at the
|
|
18
|
+
top of every script "just in case," and that preamble killed scripts
|
|
19
|
+
that only used the high-level API.
|
|
20
|
+
|
|
21
|
+
As of 0.11.3 the stub is **lazy**: ``from docx.oxml.ns import qn``
|
|
22
|
+
succeeds and returns a sentinel proxy that defers the typed error
|
|
23
|
+
until the symbol is actually called or further-attribute-accessed.
|
|
24
|
+
Scripts that import for parity but never use the symbol now run
|
|
25
|
+
cleanly; scripts that reach for ``qn("w:tcW")`` still get the
|
|
26
|
+
actionable error pointing at the high-level alternative.
|
|
27
|
+
|
|
28
|
+
The gap is documented in ``docx-studio/python-sdk/CLAUDE.md`` § "Intentionally
|
|
29
|
+
omitted" and locked into the parity matrix via
|
|
30
|
+
``tests/parity/intentional_deviations.json`` (``docx.oxml**``).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import sys
|
|
36
|
+
import types
|
|
37
|
+
from typing import Any
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class OxmlNotAvailableError(ImportError):
|
|
41
|
+
"""Raised when a ``docx.oxml.*`` symbol is actually used.
|
|
42
|
+
|
|
43
|
+
Inherits :class:`ImportError` so callers using
|
|
44
|
+
``try: from docx.oxml import X / except ImportError`` still match
|
|
45
|
+
after 0.11.3's lazy-stub change (the import itself succeeds, but
|
|
46
|
+
the first call site against the imported name raises this — and
|
|
47
|
+
code that uses ``except ImportError`` around a use-site still
|
|
48
|
+
catches it).
|
|
49
|
+
|
|
50
|
+
Use ``except OxmlNotAvailableError`` to distinguish a "no oxml
|
|
51
|
+
surface" miss from a real import-resolution failure or other
|
|
52
|
+
``ImportError`` cause.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_MESSAGE: str = (
|
|
57
|
+
"docx.oxml is not available in athena-python-docx — the SuperDoc "
|
|
58
|
+
"backend doesn't expose raw OOXML elements. Use the high-level "
|
|
59
|
+
"python-docx API (Document.add_paragraph, Run.bold, _Cell.text, …) "
|
|
60
|
+
"or the typed command surface in docx.commands for any mutation "
|
|
61
|
+
"the high-level API doesn't cover. "
|
|
62
|
+
"See docx-studio/python-sdk/CLAUDE.md § 'Intentionally omitted' for "
|
|
63
|
+
"the parity rationale."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class _LazyRaisingProxy:
|
|
68
|
+
"""Sentinel returned by the ``docx.oxml`` stub for any imported name.
|
|
69
|
+
|
|
70
|
+
Behaves as a callable, an attribute-accessible namespace, and an
|
|
71
|
+
awaitable for the union of common python-docx patterns:
|
|
72
|
+
|
|
73
|
+
* ``from docx.oxml.ns import qn`` → ``qn`` is a _LazyRaisingProxy.
|
|
74
|
+
Just importing it is a no-op. ``qn("w:tcW")`` raises with the
|
|
75
|
+
educated message.
|
|
76
|
+
* ``from docx.oxml import OxmlElement`` → same. ``OxmlElement(...)``
|
|
77
|
+
raises; ``OxmlElement.something`` raises.
|
|
78
|
+
* ``isinstance(x, OxmlElement)`` → raises (we'd rather a noisy
|
|
79
|
+
failure than silently say no, since the typed error tells the
|
|
80
|
+
caller what to do).
|
|
81
|
+
|
|
82
|
+
The proxy carries the full dotted path so the error message points
|
|
83
|
+
at exactly the offending symbol — ``docx.oxml.ns.qn`` rather than a
|
|
84
|
+
generic "docx.oxml".
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
__slots__ = ("_path",)
|
|
88
|
+
|
|
89
|
+
def __init__(self, path: str) -> None:
|
|
90
|
+
# Bypass __setattr__ guard.
|
|
91
|
+
object.__setattr__(self, "_path", path)
|
|
92
|
+
|
|
93
|
+
def _raise(self, suffix: str = "") -> None:
|
|
94
|
+
path = object.__getattribute__(self, "_path")
|
|
95
|
+
target = f"{path}{suffix}" if suffix else path
|
|
96
|
+
raise OxmlNotAvailableError(f"{target} — {_MESSAGE}")
|
|
97
|
+
|
|
98
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any: # noqa: ANN401
|
|
99
|
+
self._raise()
|
|
100
|
+
|
|
101
|
+
def __getattr__(self, name: str) -> Any: # noqa: ANN401
|
|
102
|
+
if name.startswith("__") and name.endswith("__"):
|
|
103
|
+
raise AttributeError(name)
|
|
104
|
+
self._raise(f".{name}")
|
|
105
|
+
|
|
106
|
+
def __setattr__(self, name: str, value: Any) -> None: # noqa: ANN401
|
|
107
|
+
# Block writes to the proxy so agents that try
|
|
108
|
+
# ``OxmlElement.tag = "..."`` get the typed error rather than a
|
|
109
|
+
# silent attribute set on the sentinel.
|
|
110
|
+
if name == "_path":
|
|
111
|
+
object.__setattr__(self, name, value)
|
|
112
|
+
return
|
|
113
|
+
self._raise(f".{name}")
|
|
114
|
+
|
|
115
|
+
def __repr__(self) -> str:
|
|
116
|
+
path = object.__getattribute__(self, "_path")
|
|
117
|
+
return f"<docx.oxml lazy stub {path!r} — call to raise>"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class _OxmlStubModule(types.ModuleType):
|
|
121
|
+
"""ModuleType subclass that returns :class:`_LazyRaisingProxy`
|
|
122
|
+
sentinels for any attribute access.
|
|
123
|
+
|
|
124
|
+
Installed into :data:`sys.modules` at package-init time so
|
|
125
|
+
qualified imports like ``from docx.oxml.ns import qn`` find a real
|
|
126
|
+
module object (avoiding ``ModuleNotFoundError``). The proxy
|
|
127
|
+
returned defers the typed error until the symbol is actually
|
|
128
|
+
invoked, letting top-level python-docx import blocks succeed.
|
|
129
|
+
|
|
130
|
+
No ``__slots__`` — ``types.ModuleType`` itself carries a
|
|
131
|
+
``__dict__``, so a slots declaration on a subclass is a no-op.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
def __getattr__(self, name: str) -> Any: # noqa: ANN401
|
|
135
|
+
if name.startswith("__") and name.endswith("__"):
|
|
136
|
+
# Dunder access (e.g. ``__path__`` during submodule import)
|
|
137
|
+
# must fall through to AttributeError so Python's import
|
|
138
|
+
# machinery can probe without triggering our typed error.
|
|
139
|
+
raise AttributeError(name)
|
|
140
|
+
path = self.__name__
|
|
141
|
+
proxy = _LazyRaisingProxy(f"{path}.{name}")
|
|
142
|
+
# Cache so repeated `getattr` returns the same proxy and so
|
|
143
|
+
# `from X import Y` followed by another `from X import Y`
|
|
144
|
+
# gives the same instance.
|
|
145
|
+
object.__setattr__(self, name, proxy)
|
|
146
|
+
return proxy
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# Common upstream submodule paths. Listed explicitly rather than wild-
|
|
150
|
+
# carded so adding a new one is a visible diff. Every entry maps to a
|
|
151
|
+
# single sentinel module; no per-submodule state.
|
|
152
|
+
_SUBMODULES: tuple[str, ...] = (
|
|
153
|
+
"ns",
|
|
154
|
+
"parser",
|
|
155
|
+
"element",
|
|
156
|
+
"xmlchemy",
|
|
157
|
+
"exceptions",
|
|
158
|
+
"ooxml",
|
|
159
|
+
"coreprops",
|
|
160
|
+
"document",
|
|
161
|
+
"text",
|
|
162
|
+
"table",
|
|
163
|
+
"comments",
|
|
164
|
+
"header_footer",
|
|
165
|
+
"footnote",
|
|
166
|
+
"endnote",
|
|
167
|
+
"shared",
|
|
168
|
+
"shape",
|
|
169
|
+
"section",
|
|
170
|
+
"settings",
|
|
171
|
+
"styles",
|
|
172
|
+
"numbering",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _install_stub_submodules() -> None:
|
|
177
|
+
"""Pre-populate :data:`sys.modules` with stub entries for every
|
|
178
|
+
well-known ``docx.oxml.*`` submodule.
|
|
179
|
+
|
|
180
|
+
Idempotent — re-running is a no-op for entries already installed
|
|
181
|
+
(covers the rare case of a test that reloads the package).
|
|
182
|
+
"""
|
|
183
|
+
for short in _SUBMODULES:
|
|
184
|
+
full = f"docx.oxml.{short}"
|
|
185
|
+
if full in sys.modules:
|
|
186
|
+
continue
|
|
187
|
+
sys.modules[full] = _OxmlStubModule(full)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
_install_stub_submodules()
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401
|
|
194
|
+
"""PEP 562 attribute hook for ``from docx.oxml import X``.
|
|
195
|
+
|
|
196
|
+
Submodule names (handled via :data:`sys.modules` injection in
|
|
197
|
+
:func:`_install_stub_submodules`) and dunder names fall through
|
|
198
|
+
normally. Everything else returns a :class:`_LazyRaisingProxy` so
|
|
199
|
+
the import succeeds and the typed error fires only on actual use.
|
|
200
|
+
"""
|
|
201
|
+
if name.startswith("__") and name.endswith("__"):
|
|
202
|
+
raise AttributeError(name)
|
|
203
|
+
if name in _SUBMODULES:
|
|
204
|
+
# Should already be present in sys.modules; defensive fallback
|
|
205
|
+
# so we never leak ModuleNotFoundError if the caller reloaded
|
|
206
|
+
# the package between calls.
|
|
207
|
+
full = f"docx.oxml.{name}"
|
|
208
|
+
mod = sys.modules.get(full)
|
|
209
|
+
if mod is None:
|
|
210
|
+
mod = _OxmlStubModule(full)
|
|
211
|
+
sys.modules[full] = mod
|
|
212
|
+
return mod
|
|
213
|
+
return _LazyRaisingProxy(f"docx.oxml.{name}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
__all__ = ["OxmlNotAvailableError"]
|
|
@@ -1430,40 +1430,47 @@ class _Cell:
|
|
|
1430
1430
|
def add_table(self, rows: int, cols: int) -> Table:
|
|
1431
1431
|
"""Append a nested table inside the cell.
|
|
1432
1432
|
|
|
1433
|
-
Mirrors python-docx ``_Cell.add_table(rows, cols) -> Table
|
|
1433
|
+
Mirrors python-docx ``_Cell.add_table(rows, cols) -> Table``
|
|
1434
|
+
at the API surface, but raises
|
|
1435
|
+
:class:`docx.errors.NestedTableNotSupportedError` at runtime
|
|
1436
|
+
— SuperDoc 1.8.1 has no addressable shape for "create table
|
|
1437
|
+
inside this cell" (every available anchor either targets a
|
|
1438
|
+
cell-inner paragraph SuperDoc can't resolve, or promotes the
|
|
1439
|
+
new block to the cell's parent row level). The unblock is
|
|
1440
|
+
tracked at ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md`` § 13;
|
|
1441
|
+
the same gap was the proximate cause of the
|
|
1442
|
+
``_Cell.add_paragraph`` failure fixed in 0.11.1 (#20745), and
|
|
1443
|
+
that fix worked only because ``doc.insert`` accepts a paragraph
|
|
1444
|
+
content fragment against a ``tableCell`` target — there is no
|
|
1445
|
+
analogous table-content fragment path through the current
|
|
1446
|
+
docx-studio command bus.
|
|
1447
|
+
|
|
1448
|
+
``rows`` and ``cols`` are still validated upfront so callers
|
|
1449
|
+
get the same ``ValidationError`` they would have hit before, in
|
|
1450
|
+
case they were branching on it.
|
|
1451
|
+
|
|
1434
1452
|
Note that upstream's ``_Cell.add_table`` does not take a
|
|
1435
1453
|
``width`` parameter — Word inherits cell-table widths from
|
|
1436
1454
|
layout. ``Document.add_table`` and ``Section.header.add_table``
|
|
1437
1455
|
DO take ``width`` because they're block-level.
|
|
1438
1456
|
"""
|
|
1439
|
-
from docx.
|
|
1457
|
+
from docx.errors import NestedTableNotSupportedError
|
|
1440
1458
|
|
|
1441
1459
|
if rows < 1 or cols < 1:
|
|
1442
1460
|
raise ValidationError(f"rows/cols must be >=1; got {rows}/{cols}")
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
anchor
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
anchor = {"kind": "documentEnd"}
|
|
1456
|
-
result: object = run_sync(
|
|
1457
|
-
self._table._session.doc.create.table(
|
|
1458
|
-
{"rows": rows, "columns": cols, "at": anchor},
|
|
1459
|
-
),
|
|
1461
|
+
raise NestedTableNotSupportedError(
|
|
1462
|
+
"_Cell.add_table is unsupported on SuperDoc 1.8.1. The cell "
|
|
1463
|
+
"addressing gap (SUPERDOC_UPSTREAM_REQUESTS.md § 13) means "
|
|
1464
|
+
"no anchor or content-fragment shape currently lets the SDK "
|
|
1465
|
+
"place a new table inside an existing tableCell. Workarounds: "
|
|
1466
|
+
"(a) build the table at document or section level via "
|
|
1467
|
+
"Document.add_table and reference it from cell text, or "
|
|
1468
|
+
"(b) include the nested table in the original template "
|
|
1469
|
+
"document and address its cells directly. This method will "
|
|
1470
|
+
"be reinstated once SuperDoc exposes either recursive "
|
|
1471
|
+
"paragraph-anchor lookup or a cell-scoped create.table "
|
|
1472
|
+
"variant.",
|
|
1460
1473
|
)
|
|
1461
|
-
node_id: str = _extract_inserted_node_id(result, expected_type="table") if isinstance(result, dict) else ""
|
|
1462
|
-
if not node_id:
|
|
1463
|
-
raise RuntimeError(
|
|
1464
|
-
f"Superdoc did not return nodeId for nested table: {result!r}",
|
|
1465
|
-
)
|
|
1466
|
-
return Table(session=self._table._session, node_id=node_id)
|
|
1467
1474
|
|
|
1468
1475
|
def merge(self, other_cell: "_Cell") -> "_Cell":
|
|
1469
1476
|
"""Return a merged cell created by spanning the rectangular
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "athena-python-docx"
|
|
7
|
-
version = "0.11.
|
|
7
|
+
version = "0.11.3"
|
|
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"
|
|
@@ -319,18 +319,15 @@ CASES: list[ComplexCase] = [
|
|
|
319
319
|
expected_ops=("tables.getCells", "create.paragraph"),
|
|
320
320
|
tags=("level5", "table"),
|
|
321
321
|
),
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
expected_ops=("create.table",),
|
|
332
|
-
tags=("level5", "table", "nested"),
|
|
333
|
-
),
|
|
322
|
+
# Removed in 0.11.2 (#20745 follow-up): ``_Cell.add_table`` now
|
|
323
|
+
# raises ``NestedTableNotSupportedError`` because SuperDoc 1.8.1
|
|
324
|
+
# has no addressable shape for "create new table inside this cell"
|
|
325
|
+
# — every available anchor either targets a cell-inner paragraph
|
|
326
|
+
# SuperDoc can't resolve or promotes the new block to the cell's
|
|
327
|
+
# parent row. Tracked at SUPERDOC_UPSTREAM_REQUESTS.md § 13. Pre-
|
|
328
|
+
# 0.11.2 this case "passed" by silently writing the nested table
|
|
329
|
+
# to documentEnd, which round-tripped in the fake but is wrong in
|
|
330
|
+
# production. See tests/test_cell_add_table_not_supported.py.
|
|
334
331
|
ComplexCase(
|
|
335
332
|
name="24_table_add_row_column",
|
|
336
333
|
description="Add row and column dynamically (python-docx 1.x requires width for add_column)",
|
|
@@ -745,17 +742,9 @@ CASES: list[ComplexCase] = [
|
|
|
745
742
|
),
|
|
746
743
|
|
|
747
744
|
# ---------- Level 17: deep nesting + iteration ----------
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
script=(
|
|
752
|
-
"outer = doc.add_table(rows=1, cols=1)\n"
|
|
753
|
-
"mid = outer.cell(0, 0).add_table(rows=1, cols=1)\n"
|
|
754
|
-
"inner = mid.cell(0, 0).add_table(rows=2, cols=2)\n"
|
|
755
|
-
'inner.cell(0, 0).text = "deepest"'
|
|
756
|
-
),
|
|
757
|
-
tags=("level17", "nested"),
|
|
758
|
-
),
|
|
745
|
+
# 51_nested_tables_deep removed in 0.11.2 (#20745 follow-up):
|
|
746
|
+
# _Cell.add_table now raises NestedTableNotSupportedError on
|
|
747
|
+
# SuperDoc 1.8.1; see SUPERDOC_UPSTREAM_REQUESTS.md § 13.
|
|
759
748
|
ComplexCase(
|
|
760
749
|
name="52_iterate_everything",
|
|
761
750
|
description="Create a doc then iterate sections/paragraphs/tables",
|
|
@@ -1784,20 +1773,9 @@ CASES: list[ComplexCase] = [
|
|
|
1784
1773
|
),
|
|
1785
1774
|
|
|
1786
1775
|
# ---------- Level 56: cell.tables for nested detection ----------
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
script=(
|
|
1791
|
-
"outer = doc.add_table(rows=1, cols=1)\n"
|
|
1792
|
-
"c = outer.cell(0, 0)\n"
|
|
1793
|
-
"c.add_table(rows=2, cols=2)\n"
|
|
1794
|
-
"c.add_table(rows=1, cols=1)\n"
|
|
1795
|
-
"# cell.tables should list nested tables\n"
|
|
1796
|
-
"nested = c.tables\n"
|
|
1797
|
-
"# don't assert exact count — fake may not fully reflect"
|
|
1798
|
-
),
|
|
1799
|
-
tags=("level56", "nested"),
|
|
1800
|
-
),
|
|
1776
|
+
# 103_cell_tables_enumeration removed in 0.11.2 (#20745 follow-up):
|
|
1777
|
+
# _Cell.add_table raises NestedTableNotSupportedError; see
|
|
1778
|
+
# SUPERDOC_UPSTREAM_REQUESTS.md § 13.
|
|
1801
1779
|
|
|
1802
1780
|
# ---------- Level 57: core properties pull in datetime ----------
|
|
1803
1781
|
ComplexCase(
|
|
@@ -11,18 +11,9 @@ from tests.fidelity.complex_cases import ComplexCase
|
|
|
11
11
|
|
|
12
12
|
EXTREME_CASES: list[ComplexCase] = [
|
|
13
13
|
# ---- Deep nesting ----
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
script=(
|
|
18
|
-
"current = doc.add_table(rows=1, cols=1).cell(0, 0)\n"
|
|
19
|
-
"for i in range(4):\n"
|
|
20
|
-
" nested = current.add_table(rows=1, cols=1)\n"
|
|
21
|
-
" current = nested.cell(0, 0)\n"
|
|
22
|
-
"current.text = 'deepest'"
|
|
23
|
-
),
|
|
24
|
-
tags=("extreme", "nested"),
|
|
25
|
-
),
|
|
14
|
+
# ex01_five_levels_deep_tables removed in 0.11.2 (#20745 follow-up):
|
|
15
|
+
# _Cell.add_table raises NestedTableNotSupportedError on SuperDoc
|
|
16
|
+
# 1.8.1; see SUPERDOC_UPSTREAM_REQUESTS.md § 13.
|
|
26
17
|
|
|
27
18
|
# ---- Unicode stress ----
|
|
28
19
|
ComplexCase(
|
|
@@ -305,19 +305,10 @@ REAL_WORLD_CASES: list[ComplexCase] = [
|
|
|
305
305
|
tags=("real_world", "headers", "even_odd"),
|
|
306
306
|
),
|
|
307
307
|
|
|
308
|
-
#
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
description="Nested 2x2 table inside the (0,0) cell of a parent table",
|
|
313
|
-
script=(
|
|
314
|
-
"document = doc\n"
|
|
315
|
-
"t = document.add_table(rows=2, cols=2, style='TableGrid')\n"
|
|
316
|
-
"inner = t.cell(0, 0).add_table(2, 2)\n"
|
|
317
|
-
"inner.cell(0, 0).text = 'inner'"
|
|
318
|
-
),
|
|
319
|
-
tags=("real_world", "table", "nested"),
|
|
320
|
-
),
|
|
308
|
+
# rw14_nested_cell_table removed in 0.11.2 (#20745 follow-up):
|
|
309
|
+
# _Cell.add_table now raises NestedTableNotSupportedError; the
|
|
310
|
+
# functionality requires SuperDoc upstream work tracked at
|
|
311
|
+
# SUPERDOC_UPSTREAM_REQUESTS.md § 13.
|
|
321
312
|
|
|
322
313
|
# Paragraph-style instances passed to add_paragraph (Phase A
|
|
323
314
|
# tightening). Exercises the str | ParagraphStyle | None branch of
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Pinning test for ``_Cell.add_table`` raising
|
|
2
|
+
:class:`NestedTableNotSupportedError`.
|
|
3
|
+
|
|
4
|
+
SuperDoc 1.8.1 has no addressable shape for "create new table inside
|
|
5
|
+
this cell" — ``create.table`` rejects a cell-inner paragraph anchor
|
|
6
|
+
with ``INVALID_TARGET - Expected paragraph:<id> but found
|
|
7
|
+
tableCell:<id>``, and the ``doc.insert``-based workaround used by
|
|
8
|
+
``_Cell.add_paragraph`` (paragraph fragment + ``placement: insideEnd``)
|
|
9
|
+
has no analog for table content fragments wired through the
|
|
10
|
+
docx-studio command bus. So ``_Cell.add_table`` raises a typed
|
|
11
|
+
``NestedTableNotSupportedError`` rather than silently corrupting the
|
|
12
|
+
document (the pre-0.11.2 implementation either failed with the
|
|
13
|
+
cryptic INVALID_TARGET when the cell had content or silently wrote
|
|
14
|
+
the table to documentEnd when the cell was empty).
|
|
15
|
+
|
|
16
|
+
Tracked at ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md`` § 13.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from docx.errors import NestedTableNotSupportedError, ValidationError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _make_cell(mock_session: Any, fake_sd_methods: Any) -> Any:
|
|
29
|
+
from docx.table import Table, _Cell
|
|
30
|
+
|
|
31
|
+
fake_sd_methods.scripted_returns["tables.get_cells"] = {
|
|
32
|
+
"cells": [
|
|
33
|
+
{
|
|
34
|
+
"nodeId": "cell-auto-x1",
|
|
35
|
+
"rowIndex": 0,
|
|
36
|
+
"columnIndex": 0,
|
|
37
|
+
"text": "",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
}
|
|
41
|
+
table = Table(session=mock_session, node_id="tbl-1")
|
|
42
|
+
return _Cell(table=table, row=0, col=0)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_cell_add_table_raises_nested_table_not_supported(
|
|
46
|
+
mock_session: Any, fake_sd_methods: Any
|
|
47
|
+
) -> None:
|
|
48
|
+
cell = _make_cell(mock_session, fake_sd_methods)
|
|
49
|
+
with pytest.raises(NestedTableNotSupportedError) as exc_info:
|
|
50
|
+
cell.add_table(2, 2)
|
|
51
|
+
msg = str(exc_info.value)
|
|
52
|
+
assert "SUPERDOC_UPSTREAM_REQUESTS.md § 13" in msg
|
|
53
|
+
assert "Document.add_table" in msg
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_cell_add_table_still_validates_dimensions_first(
|
|
57
|
+
mock_session: Any, fake_sd_methods: Any
|
|
58
|
+
) -> None:
|
|
59
|
+
"""``ValidationError`` for bad dimensions must still fire BEFORE the
|
|
60
|
+
NotImplementedError. Lets agents catch the more specific error
|
|
61
|
+
type without first reasoning about why the method is unsupported.
|
|
62
|
+
"""
|
|
63
|
+
cell = _make_cell(mock_session, fake_sd_methods)
|
|
64
|
+
with pytest.raises(ValidationError, match="rows/cols"):
|
|
65
|
+
cell.add_table(0, 2)
|
|
66
|
+
with pytest.raises(ValidationError, match="rows/cols"):
|
|
67
|
+
cell.add_table(2, 0)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_nested_table_error_is_a_notimplementederror(
|
|
71
|
+
mock_session: Any, fake_sd_methods: Any
|
|
72
|
+
) -> None:
|
|
73
|
+
"""``NestedTableNotSupportedError`` subclasses ``NotImplementedError``
|
|
74
|
+
so generic ``except NotImplementedError`` (a common pattern) catches
|
|
75
|
+
it without needing to import the typed class.
|
|
76
|
+
"""
|
|
77
|
+
cell = _make_cell(mock_session, fake_sd_methods)
|
|
78
|
+
with pytest.raises(NotImplementedError):
|
|
79
|
+
cell.add_table(2, 2)
|