athena-python-docx 0.5.3__tar.gz → 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/PKG-INFO +1 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/__init__.py +1 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/comments.py +20 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/document.py +31 -6
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/section.py +18 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/text.py +73 -2
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/section.py +87 -20
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/shape.py +26 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/table.py +118 -19
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/paragraph.py +163 -8
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/parfmt.py +89 -5
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/run.py +172 -8
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/tabstops.py +61 -20
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/pyproject.toml +1 -1
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/03_runs_with_formatting.json +4 -4
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/04_font_name_and_size.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/05_font_color_rgb.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/06_font_character_properties.json +0 -1
- athena_python_docx-0.6.1/tests/fidelity/op_snapshots/07_font_subscript_superscript.json +7 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/08_font_highlight.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/102_text_with_embedded_special_chars.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/14_run_add_tab_and_break.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/15_run_add_break_page.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/16_paragraph_clear_and_insert_before.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/35_full_report.json +0 -4
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/36_replace_text_in_paragraph.json +0 -1
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/07_font_subscript_superscript.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/37_iterate_runs_and_format_all_bold.json +3 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/38_font_all_properties.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/46_run_text_setter_round_trip.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/47_font_size_round_trip.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/48_font_color_round_trip.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/49_resume_layout.json +0 -7
- athena_python_docx-0.6.1/tests/fidelity/op_snapshots/54_empty_everything.json +4 -0
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/03_runs_with_formatting.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/55_single_character_runs.json +2 -5
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/56_everything_in_one.json +0 -6
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/57_runs_after_multiple_text_appends.json +0 -3
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/55_single_character_runs.json → athena_python_docx-0.6.1/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +3 -6
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/68_invoice.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/69_newsletter.json +0 -9
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/71_academic_paper.json +0 -2
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/72_legal_contract.json +0 -6
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/74_paragraph_with_10_runs.json +0 -10
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/76_rgbcolor_from_string.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/80_apply_style_after_add_run.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/82_add_text_on_existing_run.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/83_clear_then_repopulate_paragraph.json +0 -2
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/86_font_read_unset_returns_none.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/93_font_bool_reads_after_set.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/96_paragraph_contains_page_break.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/99_run_add_picture_from_bytes.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex02_unicode_everywhere.json +0 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex06_hundred_tiny_runs.json +0 -100
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex07_every_font_boolean.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex16_runs_interleaved_with_breaks.json +0 -4
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex17_all_break_kinds.json +0 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex19_mutate_all_runs.json +0 -15
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex20_kitchen_sink_v2.json +0 -22
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega01_book_chapter.json +0 -8
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega02_research_proposal.json +0 -4
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega03_financial_statement.json +0 -1
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega04_recipe_card.json +0 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega05_user_manual.json +0 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega06_complex_newsletter.json +0 -17
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega08_product_catalog.json +0 -15
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega09_signed_contract.json +0 -11
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega10_api_documentation.json +0 -7
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw01_official_quickstart.json +0 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw03_character_formatting.json +0 -2
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw06_meeting_minutes.json +0 -4
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw07_dense_formatting_demo.json +0 -6
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw09_bulk_run_iteration.json +0 -30
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/introspect.py +14 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/reports/GAP_ANALYSIS.md +28 -3
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/reports/gap_report.json +1672 -10
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/snapshots/athena_latest.json +230 -15
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/snapshots/upstream_python_docx_1.2.0.json +4046 -3115
- athena_python_docx-0.6.1/tests/test_collapsed_range_format.py +190 -0
- athena_python_docx-0.6.1/tests/test_paragraph_text_len_cache.py +161 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_add_paragraph_style.py +67 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_add_run.py +90 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_cell_add_paragraph.py +47 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_comments_add_comment.py +71 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_enum_section.py +83 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_inline_shape.py +105 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_insert_paragraph_before.py +61 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_paragraph_strict.py +170 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_paragraph_style.py +17 -9
- athena_python_docx-0.6.1/tests/test_silent_stub_paragraph_style_strict.py +93 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_parfmt.py +367 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_row_col_cell.py +181 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_run_add_break.py +82 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_run_style.py +57 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_run_style_strict.py +71 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_run_text.py +71 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_run_underline.py +123 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_section_dimensions.py +96 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_section_onoff.py +83 -0
- athena_python_docx-0.6.1/tests/test_silent_stub_table_layout.py +153 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/uv.lock +1 -1
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/54_empty_everything.json +0 -6
- athena_python_docx-0.5.3/tests/fidelity/op_snapshots/58_modify_runs_in_place.json +0 -18
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/.gitignore +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/CLAUDE.md +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/README.md +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_batching.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_buffer.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_http.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_http_doc.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_image_utils.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/_ptc.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/api.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/client.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/commands.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/style.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/enum/table.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/errors.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/exceptions.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/opc/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/opc/coreprops.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/revisions.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/settings.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/shared.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/style.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/styles/styles.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/font.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/hyperlink.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/text/pagebreak.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/docx/typing.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/publish.sh +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/release.sh +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/scripts/round_trip_smoke.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/conftest.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/METHODOLOGY.md +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ab_probe_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ab_probe_runner.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/auto_gen_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/binary_round_trip.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/complex_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/coverage_report.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/extreme_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/fake_session.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/local_runner.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/mega_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshot.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/01_basic_paragraph.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/02_multiple_headings.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/09_paragraph_alignment.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/100_table_negative_indexing.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/101_table_cells_flat_iteration.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/103_cell_tables_enumeration.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/104_core_properties_datetime.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/105_default_one_section.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/106_heading_paragraph_format.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/107_varying_row_heights.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/10_paragraph_indents.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/11_paragraph_spacing.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/12_paragraph_keep_options.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/13_paragraph_tab_stops.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/17_table_basic.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/18_table_cell_text.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/19_table_row_column_sizing.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/20_table_cell_vertical_alignment.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/21_table_alignment_and_autofit.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/22_table_cell_paragraphs_iteration.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/23_nested_table.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/24_table_add_row_column.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/25_table_merge_cells.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/26_section_page_setup.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/27_section_margins.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/28_section_add_new.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/29_section_headers_linked.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/30_styles_iteration.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/31_styles_lookup_and_default.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/32_styles_add_paragraph_style.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/33_core_properties_set_and_get.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/34_inline_shapes_iterate_empty.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/39_large_body_100_paragraphs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/40_large_table_10x10.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/41_unicode_and_emoji.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/42_very_long_paragraph.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/43_paragraph_text_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/44_paragraph_alignment_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/45_cell_text_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/50_multi_section_doc.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/51_nested_tables_deep.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/52_iterate_everything.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/53_apply_style_to_paragraphs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/59_indent_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/60_space_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/61_cell_paragraph_with_runs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/62_many_cell_paragraphs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/63_table_style_round_trip.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/64_many_sections.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/65_20x20_table_formatted.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/66_toc_like_structure.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/67_paragraph_insert_before_chain.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/70_add_and_iterate_back.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/73_form_with_many_tables.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/75_paragraph_negative_first_line_indent.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/77_length_unit_conversions.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/78_paragraph_copy_style.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/79_bulk_cell_formatting.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/81_multi_page_with_breaks.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/84_table_reread_row_count.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/85_header_footer_access.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/87_500_paragraph_doc.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/88_mixed_content_iteration.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/89_alignment_clear_via_none.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/90_cell_add_paragraph_styled.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/91_many_small_tables.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/92_margins_every_section.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/94_page_break_before_paragraph.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/95_paragraph_hyperlinks_empty.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/97_document_styles_by_key.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/98_style_contains_check.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex01_five_levels_deep_tables.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex03_1000_paragraphs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex04_50x50_table.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex05_long_text_in_cell.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex08_many_continuous_sections.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex09_many_tab_stops.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex10_complex_bom.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex11_banded_rows_formatting.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex12_section_reconfigure.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex13_cell_with_10_paragraphs.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex14_styled_report_table.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex15_paragraph_all_format_props.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/ex18_read_back_large_doc.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/mega07_budget_spreadsheet.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw02_paragraph_style_list.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw04_section_page_setup.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw05_toc_pattern.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw08_table_merged_header.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw10_colored_grid_table.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw11_header_text.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw12_first_page_footer.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw13_even_page_header.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw14_nested_cell_table.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/op_snapshots/rw15_paragraph_style_instance.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/ours_spec.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/parity_crawl.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/parity_diff.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/real_world_cases.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/round_trip_tests.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/runner.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/fidelity/stock_spec.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/README.md +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/__init__.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/baseline_gaps.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/compare.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/intentional_deviations.json +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/run_parity.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/parity/test_parity_gap.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_batching_perf.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_buffer.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_command_dataclasses.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_commands.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_comments.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_document_create.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_http_transport.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_iter_inner_content.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_merged_cells.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_parity_misc.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_parity_round2.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_a_behavior.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_b_headers_footers.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_phase_c_tables.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_pr19766_review_fixes.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_ptc.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_revisions.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_add_picture.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_comments_get.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_document_audit.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_document_element.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_font_audit.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_header_footer.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_hyperlink.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_misc.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_run_bool_setters.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_section_audit.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_settings.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_shared_audit.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_style.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_styles.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_audit.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_cell.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_silent_stub_table_dimensions.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_smoke_integration.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_acceptance.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_font.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_style_setters_contract.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_wire_contract.py +0 -0
- {athena_python_docx-0.5.3 → athena_python_docx-0.6.1}/tests/test_zod_wire_contract.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -314,6 +314,26 @@ class Comments:
|
|
|
314
314
|
Use :meth:`Document.add_comment` to thread a run-anchored
|
|
315
315
|
target — this method creates an unanchored comment.
|
|
316
316
|
"""
|
|
317
|
+
# python-docx 1.x routes ``text`` / ``author`` / ``initials``
|
|
318
|
+
# through lxml's element setters which TypeError on non-str.
|
|
319
|
+
# Was: any value shipped to wire (text) or stashed as-is on
|
|
320
|
+
# the local info dict (author/initials) — caller's intent was
|
|
321
|
+
# lost when they passed a wrong type.
|
|
322
|
+
if not isinstance(text, str):
|
|
323
|
+
raise TypeError(
|
|
324
|
+
f"Comments.add_comment text requires str; got "
|
|
325
|
+
f"{type(text).__name__} {text!r}",
|
|
326
|
+
)
|
|
327
|
+
if not isinstance(author, str):
|
|
328
|
+
raise TypeError(
|
|
329
|
+
f"Comments.add_comment author requires str; got "
|
|
330
|
+
f"{type(author).__name__} {author!r}",
|
|
331
|
+
)
|
|
332
|
+
if initials is not None and not isinstance(initials, str):
|
|
333
|
+
raise TypeError(
|
|
334
|
+
f"Comments.add_comment initials requires str or None; "
|
|
335
|
+
f"got {type(initials).__name__} {initials!r}",
|
|
336
|
+
)
|
|
317
337
|
result: object = run_sync(
|
|
318
338
|
self._session.doc.comments.create({"text": text}),
|
|
319
339
|
)
|
|
@@ -596,9 +596,24 @@ class Document:
|
|
|
596
596
|
|
|
597
597
|
# Coerce ParagraphStyle instances to their style id so the rest
|
|
598
598
|
# of this method can treat `style` as an Optional[str].
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
599
|
+
# python-docx 1.x accepts ``str | ParagraphStyle | None`` and
|
|
600
|
+
# raises ``TypeError`` at the style-lookup layer for anything
|
|
601
|
+
# else. Mirror that — the previous code accepted ``style`` as
|
|
602
|
+
# the literal value when it wasn't a ParagraphStyle, so e.g.
|
|
603
|
+
# ``add_paragraph(style=42)`` shipped ``42`` as the style id.
|
|
604
|
+
style_str: str | None
|
|
605
|
+
if style is None:
|
|
606
|
+
style_str = None
|
|
607
|
+
elif isinstance(style, ParagraphStyle):
|
|
608
|
+
style_str = style.style_id
|
|
609
|
+
elif isinstance(style, str):
|
|
610
|
+
style_str = style
|
|
611
|
+
else:
|
|
612
|
+
raise TypeError(
|
|
613
|
+
f"Document.add_paragraph style requires str, "
|
|
614
|
+
f"ParagraphStyle, or None; got "
|
|
615
|
+
f"{type(style).__name__} {style!r}",
|
|
616
|
+
)
|
|
602
617
|
|
|
603
618
|
# Use Superdoc's canonical primitive `doc.create.paragraph`. It
|
|
604
619
|
# accepts an `at` anchor and a `text` body; an empty `text` creates
|
|
@@ -624,8 +639,9 @@ class Document:
|
|
|
624
639
|
# heavy lifting.
|
|
625
640
|
normalized: str = self._normalize_text(text)
|
|
626
641
|
has_control_chars = any(ch in "\t\n\r" for ch in normalized)
|
|
642
|
+
wire_text: str = "" if has_control_chars else normalized
|
|
627
643
|
params: dict = {
|
|
628
|
-
"text":
|
|
644
|
+
"text": wire_text,
|
|
629
645
|
"at": {"kind": "documentEnd"},
|
|
630
646
|
}
|
|
631
647
|
# When inside ``with doc.batch():`` we pre-assign a client UUID
|
|
@@ -650,8 +666,13 @@ class Document:
|
|
|
650
666
|
raise RuntimeError(
|
|
651
667
|
f"Superdoc did not return a nodeId for add_paragraph: {result!r}",
|
|
652
668
|
)
|
|
669
|
+
# Seed the text-length cache so the next ``p.add_run(...)``
|
|
670
|
+
# call can skip its ``get_node_by_id`` HTTP round-trip.
|
|
653
671
|
para = Paragraph(
|
|
654
|
-
session=self._session,
|
|
672
|
+
session=self._session,
|
|
673
|
+
node_id=node_id,
|
|
674
|
+
node_type="paragraph",
|
|
675
|
+
text_len=len(wire_text),
|
|
655
676
|
)
|
|
656
677
|
if client_node_id is not None:
|
|
657
678
|
self._register_proxy_for_batch(client_node_id, para)
|
|
@@ -722,6 +743,7 @@ class Document:
|
|
|
722
743
|
session=self._session,
|
|
723
744
|
node_id=node_id,
|
|
724
745
|
node_type="paragraph",
|
|
746
|
+
text_len=len(wire_text),
|
|
725
747
|
)
|
|
726
748
|
if client_node_id is not None:
|
|
727
749
|
self._register_proxy_for_batch(client_node_id, paragraph)
|
|
@@ -753,7 +775,10 @@ class Document:
|
|
|
753
775
|
f"Superdoc did not return a nodeId for add_heading: {result!r}",
|
|
754
776
|
)
|
|
755
777
|
heading = Paragraph(
|
|
756
|
-
session=self._session,
|
|
778
|
+
session=self._session,
|
|
779
|
+
node_id=node_id,
|
|
780
|
+
node_type="heading",
|
|
781
|
+
text_len=len(wire_text),
|
|
757
782
|
)
|
|
758
783
|
if client_node_id is not None:
|
|
759
784
|
self._register_proxy_for_batch(client_node_id, heading)
|
|
@@ -4,6 +4,17 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
|
|
7
|
+
from docx.enum.text import _warn_enum_coercion
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"WD_HEADER_FOOTER",
|
|
11
|
+
"WD_HEADER_FOOTER_INDEX",
|
|
12
|
+
"WD_ORIENT",
|
|
13
|
+
"WD_ORIENTATION",
|
|
14
|
+
"WD_SECTION",
|
|
15
|
+
"WD_SECTION_START",
|
|
16
|
+
]
|
|
17
|
+
|
|
7
18
|
|
|
8
19
|
class WD_ORIENTATION(Enum):
|
|
9
20
|
PORTRAIT = "portrait"
|
|
@@ -31,6 +42,13 @@ class WD_SECTION_START(Enum):
|
|
|
31
42
|
return "evenPage"
|
|
32
43
|
if self == WD_SECTION_START.ODD_PAGE:
|
|
33
44
|
return "oddPage"
|
|
45
|
+
if self == WD_SECTION_START.NEW_PAGE:
|
|
46
|
+
return "nextPage"
|
|
47
|
+
# NEW_COLUMN — SuperDoc 1.8 doesn't have a column-break section
|
|
48
|
+
# type, so we collapse to "nextPage" but emit
|
|
49
|
+
# PendingEnumCoercionWarning so callers don't silently get a
|
|
50
|
+
# page break when they asked for a column break.
|
|
51
|
+
_warn_enum_coercion(self, "nextPage")
|
|
34
52
|
return "nextPage"
|
|
35
53
|
|
|
36
54
|
|
|
@@ -2,14 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
Values map to Superdoc primitives where supported; unmapped values
|
|
4
4
|
(e.g. Thai/Arabic justification variants) still parse but serialize to
|
|
5
|
-
their best Superdoc equivalent
|
|
5
|
+
their best Superdoc equivalent and emit
|
|
6
|
+
:class:`PendingEnumCoercionWarning` so the caller knows the wire-level
|
|
7
|
+
intent was downgraded.
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
10
|
from __future__ import annotations
|
|
9
11
|
|
|
12
|
+
import warnings
|
|
10
13
|
from enum import Enum
|
|
11
14
|
|
|
12
15
|
|
|
16
|
+
_INT_TO_ALIGN: "dict[int, str]" = {
|
|
17
|
+
0: "LEFT",
|
|
18
|
+
1: "CENTER",
|
|
19
|
+
2: "RIGHT",
|
|
20
|
+
3: "JUSTIFY",
|
|
21
|
+
4: "DISTRIBUTE",
|
|
22
|
+
5: "JUSTIFY_MED",
|
|
23
|
+
7: "JUSTIFY_HI",
|
|
24
|
+
8: "JUSTIFY_LOW",
|
|
25
|
+
9: "THAI_JUSTIFY",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PendingEnumCoercionWarning(UserWarning):
|
|
30
|
+
"""Emitted when an enum member's :meth:`to_superdoc` collapses the
|
|
31
|
+
value to a different SuperDoc-supported primitive.
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
- ``WD_ALIGN_PARAGRAPH.THAI_JUSTIFY.to_superdoc()`` returns
|
|
35
|
+
``"justify"`` because SuperDoc 1.8's ``set_alignment`` rejects
|
|
36
|
+
``thaiJustify``.
|
|
37
|
+
- ``WD_TAB_ALIGNMENT.CLEAR.to_superdoc()`` returns ``"left"``
|
|
38
|
+
because SuperDoc has no equivalent clear/end/num/start tab
|
|
39
|
+
vocabulary.
|
|
40
|
+
|
|
41
|
+
Tracked in ``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``. Pin so a
|
|
42
|
+
future SuperDoc that lands the full vocabulary can flip the
|
|
43
|
+
coercion off and these warnings disappear.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _warn_enum_coercion(enum_member: object, fallback: str) -> None:
|
|
48
|
+
"""Emit a single warning identifying which enum member got
|
|
49
|
+
coerced to which SuperDoc primitive."""
|
|
50
|
+
warnings.warn(
|
|
51
|
+
f"{enum_member!r}.to_superdoc() returns {fallback!r} — "
|
|
52
|
+
f"SuperDoc 1.8 doesn't surface this value, so the wire ships "
|
|
53
|
+
f"the closest supported primitive. The visual result may "
|
|
54
|
+
f"differ from python-docx. Tracked in "
|
|
55
|
+
f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
|
|
56
|
+
PendingEnumCoercionWarning,
|
|
57
|
+
stacklevel=3,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
13
61
|
class WD_ALIGN_PARAGRAPH(Enum):
|
|
14
62
|
"""Paragraph alignment (justification)."""
|
|
15
63
|
|
|
@@ -23,10 +71,27 @@ class WD_ALIGN_PARAGRAPH(Enum):
|
|
|
23
71
|
JUSTIFY_LOW = "justifyLow"
|
|
24
72
|
THAI_JUSTIFY = "thaiJustify"
|
|
25
73
|
|
|
74
|
+
@classmethod
|
|
75
|
+
def from_int(cls, value: int) -> "WD_ALIGN_PARAGRAPH | None":
|
|
76
|
+
"""Coerce a python-docx-style int alignment to the enum.
|
|
77
|
+
|
|
78
|
+
python-docx 1.x's ``WD_ALIGN_PARAGRAPH`` is keyed on int (its
|
|
79
|
+
``BaseXmlEnum`` mapping: LEFT=0, CENTER=1, RIGHT=2, JUSTIFY=3,
|
|
80
|
+
DISTRIBUTE=4, JUSTIFY_MED=5, JUSTIFY_HI=7, JUSTIFY_LOW=8,
|
|
81
|
+
THAI_JUSTIFY=9). Callers passing ``paragraph.alignment = 1``
|
|
82
|
+
get CENTER. We mirror that without changing our enum's
|
|
83
|
+
string-valued definition.
|
|
84
|
+
"""
|
|
85
|
+
name = _INT_TO_ALIGN.get(value)
|
|
86
|
+
return getattr(cls, name) if name is not None else None
|
|
87
|
+
|
|
26
88
|
def to_superdoc(self) -> str:
|
|
27
89
|
# Superdoc only supports left/center/right/justify; coerce the
|
|
28
90
|
# distributed/thai variants to "justify" so set_alignment doesn't
|
|
29
|
-
# reject them.
|
|
91
|
+
# reject them. Emit PendingEnumCoercionWarning so the caller
|
|
92
|
+
# learns the wire-level intent was downgraded (silently shipping
|
|
93
|
+
# "justify" when the user asked for thaiJustify is the silent
|
|
94
|
+
# stub the parity loop is hunting).
|
|
30
95
|
if self in (
|
|
31
96
|
WD_ALIGN_PARAGRAPH.DISTRIBUTE,
|
|
32
97
|
WD_ALIGN_PARAGRAPH.JUSTIFY_MED,
|
|
@@ -34,6 +99,7 @@ class WD_ALIGN_PARAGRAPH(Enum):
|
|
|
34
99
|
WD_ALIGN_PARAGRAPH.JUSTIFY_LOW,
|
|
35
100
|
WD_ALIGN_PARAGRAPH.THAI_JUSTIFY,
|
|
36
101
|
):
|
|
102
|
+
_warn_enum_coercion(self, "justify")
|
|
37
103
|
return "justify"
|
|
38
104
|
return self.value
|
|
39
105
|
|
|
@@ -82,6 +148,10 @@ class WD_TAB_ALIGNMENT(Enum):
|
|
|
82
148
|
START = "start"
|
|
83
149
|
|
|
84
150
|
def to_superdoc(self) -> str:
|
|
151
|
+
# Superdoc only supports left/center/right/decimal/bar for tab
|
|
152
|
+
# alignment. ``LIST`` / ``CLEAR`` / ``END`` / ``NUM`` / ``START``
|
|
153
|
+
# are upstream-only — emit PendingEnumCoercionWarning so callers
|
|
154
|
+
# learn the wire-level intent was downgraded to ``"left"``.
|
|
85
155
|
if self in (
|
|
86
156
|
WD_TAB_ALIGNMENT.LIST,
|
|
87
157
|
WD_TAB_ALIGNMENT.CLEAR,
|
|
@@ -89,6 +159,7 @@ class WD_TAB_ALIGNMENT(Enum):
|
|
|
89
159
|
WD_TAB_ALIGNMENT.NUM,
|
|
90
160
|
WD_TAB_ALIGNMENT.START,
|
|
91
161
|
):
|
|
162
|
+
_warn_enum_coercion(self, "left")
|
|
92
163
|
return "left"
|
|
93
164
|
return self.value
|
|
94
165
|
|
|
@@ -83,6 +83,66 @@ def _emu_to_pt(emu: int) -> float:
|
|
|
83
83
|
return emu / 12700.0
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
def _reject_none_dimension(prop: str, value: object) -> None:
|
|
87
|
+
"""Raise ``TypeError`` if ``value`` is None for a dimension setter
|
|
88
|
+
that python-docx 1.2.0 doesn't accept None for.
|
|
89
|
+
|
|
90
|
+
Upstream ``Section.page_width = None`` (and every margin /
|
|
91
|
+
header_distance / footer_distance / gutter setter) routes through
|
|
92
|
+
``Emu(value).twips`` which raises ``TypeError`` on ``None``. Our
|
|
93
|
+
setters previously early-returned silently, swallowing the
|
|
94
|
+
intent. Raise to match upstream behavior — callers who actually
|
|
95
|
+
want a clear must pass ``Inches(0)`` (or similar) explicitly.
|
|
96
|
+
"""
|
|
97
|
+
if value is None:
|
|
98
|
+
raise TypeError(
|
|
99
|
+
f"Section.{prop} = None is not supported. python-docx "
|
|
100
|
+
f"1.2.0 raises TypeError here too — its Emu(None).twips "
|
|
101
|
+
f"fails with the same shape. Pass an explicit Length "
|
|
102
|
+
f"(e.g. Inches(0)) if you want to zero the dimension."
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class PendingSectionOnOffClearWarning(UserWarning):
|
|
107
|
+
"""Emitted when ``Section.different_first_page_header_footer = None``.
|
|
108
|
+
|
|
109
|
+
python-docx 1.x semantics: ``None`` clears the OOXML
|
|
110
|
+
``<w:titlePg/>`` element back to inherited. SuperDoc 1.8's
|
|
111
|
+
``sections.set_title_page`` only accepts ``enabled: bool`` — the
|
|
112
|
+
wire can't represent the clear-intent. The warning surfaces
|
|
113
|
+
silent-divergence. Tracked in
|
|
114
|
+
``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _warn_section_onoff_clear(prop: str) -> None:
|
|
119
|
+
warnings.warn(
|
|
120
|
+
f"Section.{prop} = None was IGNORED — SuperDoc 1.8 has no "
|
|
121
|
+
f"clear-op for this OnOff property. The section keeps its "
|
|
122
|
+
f"previous value. Tracked in "
|
|
123
|
+
f"docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
|
|
124
|
+
PendingSectionOnOffClearWarning,
|
|
125
|
+
stacklevel=3,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _require_section_bool(prop: str, value: object) -> bool:
|
|
130
|
+
"""Reject non-bool input on Section OnOff setters.
|
|
131
|
+
|
|
132
|
+
python-docx 1.x's ``_OnOff`` typed-attribute setter raises
|
|
133
|
+
``ValueError`` for non-bool input. Our previous ``bool(value)``
|
|
134
|
+
coercion silently turned ``"yes"`` / ``1`` / ``[]`` into True/False
|
|
135
|
+
without surfacing the type mismatch.
|
|
136
|
+
"""
|
|
137
|
+
if not isinstance(value, bool):
|
|
138
|
+
raise TypeError(
|
|
139
|
+
f"Section.{prop} requires bool or None; got "
|
|
140
|
+
f"{type(value).__name__} {value!r}. python-docx 1.x's "
|
|
141
|
+
f"``_OnOff`` setter rejects truthy non-bool here too.",
|
|
142
|
+
)
|
|
143
|
+
return value
|
|
144
|
+
|
|
145
|
+
|
|
86
146
|
class Section:
|
|
87
147
|
"""A document section — page size, margins, headers/footers, break type."""
|
|
88
148
|
|
|
@@ -124,8 +184,7 @@ class Section:
|
|
|
124
184
|
|
|
125
185
|
@page_width.setter
|
|
126
186
|
def page_width(self, value: "Length | int | None") -> None:
|
|
127
|
-
|
|
128
|
-
return
|
|
187
|
+
_reject_none_dimension("page_width", value)
|
|
129
188
|
pt = _emu_to_pt(_emu_from(value))
|
|
130
189
|
self._set_page_setup(width=pt)
|
|
131
190
|
|
|
@@ -140,8 +199,7 @@ class Section:
|
|
|
140
199
|
|
|
141
200
|
@page_height.setter
|
|
142
201
|
def page_height(self, value: "Length | int | None") -> None:
|
|
143
|
-
|
|
144
|
-
return
|
|
202
|
+
_reject_none_dimension("page_height", value)
|
|
145
203
|
pt = _emu_to_pt(_emu_from(value))
|
|
146
204
|
self._set_page_setup(height=pt)
|
|
147
205
|
|
|
@@ -201,8 +259,7 @@ class Section:
|
|
|
201
259
|
|
|
202
260
|
@left_margin.setter
|
|
203
261
|
def left_margin(self, value: "Length | int | None") -> None:
|
|
204
|
-
|
|
205
|
-
return
|
|
262
|
+
_reject_none_dimension("left_margin", value)
|
|
206
263
|
self._set_margins(left=_emu_to_pt(_emu_from(value)))
|
|
207
264
|
|
|
208
265
|
@property
|
|
@@ -211,8 +268,7 @@ class Section:
|
|
|
211
268
|
|
|
212
269
|
@right_margin.setter
|
|
213
270
|
def right_margin(self, value: "Length | int | None") -> None:
|
|
214
|
-
|
|
215
|
-
return
|
|
271
|
+
_reject_none_dimension("right_margin", value)
|
|
216
272
|
self._set_margins(right=_emu_to_pt(_emu_from(value)))
|
|
217
273
|
|
|
218
274
|
@property
|
|
@@ -221,8 +277,7 @@ class Section:
|
|
|
221
277
|
|
|
222
278
|
@top_margin.setter
|
|
223
279
|
def top_margin(self, value: "Length | int | None") -> None:
|
|
224
|
-
|
|
225
|
-
return
|
|
280
|
+
_reject_none_dimension("top_margin", value)
|
|
226
281
|
self._set_margins(top=_emu_to_pt(_emu_from(value)))
|
|
227
282
|
|
|
228
283
|
@property
|
|
@@ -231,8 +286,7 @@ class Section:
|
|
|
231
286
|
|
|
232
287
|
@bottom_margin.setter
|
|
233
288
|
def bottom_margin(self, value: "Length | int | None") -> None:
|
|
234
|
-
|
|
235
|
-
return
|
|
289
|
+
_reject_none_dimension("bottom_margin", value)
|
|
236
290
|
self._set_margins(bottom=_emu_to_pt(_emu_from(value)))
|
|
237
291
|
|
|
238
292
|
@property
|
|
@@ -241,8 +295,7 @@ class Section:
|
|
|
241
295
|
|
|
242
296
|
@gutter.setter
|
|
243
297
|
def gutter(self, value: "Length | int | None") -> None:
|
|
244
|
-
|
|
245
|
-
return
|
|
298
|
+
_reject_none_dimension("gutter", value)
|
|
246
299
|
self._set_margins(gutter=_emu_to_pt(_emu_from(value)))
|
|
247
300
|
|
|
248
301
|
@property
|
|
@@ -256,8 +309,7 @@ class Section:
|
|
|
256
309
|
|
|
257
310
|
@header_distance.setter
|
|
258
311
|
def header_distance(self, value: "Length | int | None") -> None:
|
|
259
|
-
|
|
260
|
-
return
|
|
312
|
+
_reject_none_dimension("header_distance", value)
|
|
261
313
|
run_sync(
|
|
262
314
|
self._session.doc.sections.set_header_footer_margins(
|
|
263
315
|
{"target": self._address, "header": _emu_to_pt(_emu_from(value))},
|
|
@@ -275,8 +327,7 @@ class Section:
|
|
|
275
327
|
|
|
276
328
|
@footer_distance.setter
|
|
277
329
|
def footer_distance(self, value: "Length | int | None") -> None:
|
|
278
|
-
|
|
279
|
-
return
|
|
330
|
+
_reject_none_dimension("footer_distance", value)
|
|
280
331
|
run_sync(
|
|
281
332
|
self._session.doc.sections.set_header_footer_margins(
|
|
282
333
|
{"target": self._address, "footer": _emu_to_pt(_emu_from(value))},
|
|
@@ -335,14 +386,18 @@ class Section:
|
|
|
335
386
|
@different_first_page_header_footer.setter
|
|
336
387
|
def different_first_page_header_footer(self, value: bool | None) -> None:
|
|
337
388
|
if value is None:
|
|
389
|
+
_warn_section_onoff_clear("different_first_page_header_footer")
|
|
338
390
|
return
|
|
391
|
+
enabled = _require_section_bool(
|
|
392
|
+
"different_first_page_header_footer", value
|
|
393
|
+
)
|
|
339
394
|
run_sync(
|
|
340
395
|
self._session.doc.sections.set_title_page(
|
|
341
396
|
# SuperDoc's wire field is ``enabled`` (DocSectionsSet
|
|
342
397
|
# TitlePageParams). The earlier ``titlePage`` name was
|
|
343
398
|
# rejected silently because the apps/api applier punts
|
|
344
399
|
# SuperDoc's strict types via ``AnyDoc``.
|
|
345
|
-
{"target": self._address, "enabled":
|
|
400
|
+
{"target": self._address, "enabled": enabled},
|
|
346
401
|
),
|
|
347
402
|
)
|
|
348
403
|
|
|
@@ -622,8 +677,20 @@ class _HeaderFooter:
|
|
|
622
677
|
style_str = None
|
|
623
678
|
elif isinstance(style, ParagraphStyle):
|
|
624
679
|
style_str = style.style_id
|
|
680
|
+
elif isinstance(style, str):
|
|
681
|
+
style_str = style
|
|
625
682
|
else:
|
|
626
|
-
|
|
683
|
+
# python-docx 1.x's ``add_paragraph(style=...)`` accepts
|
|
684
|
+
# ``str | ParagraphStyle | None`` and raises ``TypeError``
|
|
685
|
+
# at the style-lookup layer for anything else. The
|
|
686
|
+
# previous ``str(style)`` silently shipped garbage like
|
|
687
|
+
# ``<MyStyle object at 0x...>`` as a style id, which
|
|
688
|
+
# SuperDoc would swallow or reject without a clear signal.
|
|
689
|
+
raise TypeError(
|
|
690
|
+
f"_HeaderFooter.add_paragraph style requires str, "
|
|
691
|
+
f"ParagraphStyle, or None; got "
|
|
692
|
+
f"{type(style).__name__} {style!r}",
|
|
693
|
+
)
|
|
627
694
|
|
|
628
695
|
result: object = run_sync(
|
|
629
696
|
self._section._session.doc.create.paragraph(
|
|
@@ -7,6 +7,7 @@ to image binary / metadata round-trips through `doc.images.get`.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import base64
|
|
10
|
+
import warnings
|
|
10
11
|
from typing import TYPE_CHECKING
|
|
11
12
|
|
|
12
13
|
from docx._batching import run_sync
|
|
@@ -16,6 +17,29 @@ if TYPE_CHECKING:
|
|
|
16
17
|
from docx.client import Session
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
class PendingInlineShapeClearWarning(UserWarning):
|
|
21
|
+
"""Emitted when ``InlineShape.width`` or ``.height`` is set to
|
|
22
|
+
``None`` (python-docx semantics: "revert to natural sizing").
|
|
23
|
+
|
|
24
|
+
SuperDoc 1.8 has no clear-op for image dimensions — its
|
|
25
|
+
``images.setSize`` requires explicit ``width`` and ``height``. The
|
|
26
|
+
SDK can't represent a "revert to natural" intent on the wire, so
|
|
27
|
+
``image.width = None`` is a no-op. The warning surfaces the
|
|
28
|
+
silent-divergence pattern so agent runs see the gap. Tracked in
|
|
29
|
+
``docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md``.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _warn_inline_shape_clear(prop: str) -> None:
|
|
34
|
+
warnings.warn(
|
|
35
|
+
f"InlineShape.{prop} = None was IGNORED — SuperDoc 1.8 has no "
|
|
36
|
+
f"clear-op for image dimensions. The image keeps its previous "
|
|
37
|
+
f"size. Tracked in docx-studio/SUPERDOC_UPSTREAM_REQUESTS.md.",
|
|
38
|
+
PendingInlineShapeClearWarning,
|
|
39
|
+
stacklevel=3,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
19
43
|
def _strip_data_uri(src: str) -> tuple[bytes, str | None]:
|
|
20
44
|
"""If ``src`` is a ``data:`` URI, return (decoded_bytes, mime).
|
|
21
45
|
Otherwise return ``(b"", None)``."""
|
|
@@ -63,6 +87,7 @@ class InlineShape:
|
|
|
63
87
|
@width.setter
|
|
64
88
|
def width(self, value: "Length | int | None") -> None:
|
|
65
89
|
if value is None:
|
|
90
|
+
_warn_inline_shape_clear("width")
|
|
66
91
|
return
|
|
67
92
|
pt: float = value.pt if isinstance(value, Length) else float(value) / 12700.0
|
|
68
93
|
h = self.height
|
|
@@ -92,6 +117,7 @@ class InlineShape:
|
|
|
92
117
|
@height.setter
|
|
93
118
|
def height(self, value: "Length | int | None") -> None:
|
|
94
119
|
if value is None:
|
|
120
|
+
_warn_inline_shape_clear("height")
|
|
95
121
|
return
|
|
96
122
|
pt: float = value.pt if isinstance(value, Length) else float(value) / 12700.0
|
|
97
123
|
w = self.width
|