python-hwpx 6.8.0__tar.gz → 6.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_hwpx-6.8.0/src/python_hwpx.egg-info → python_hwpx-6.9.0}/PKG-INFO +9 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/README.md +8 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/pyproject.toml +7 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/fields.py +1 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/layout.py +46 -25
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/media.py +45 -8
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/memos.py +3 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/shapes.py +2 -2
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/tables.py +49 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/shapes.py +15 -7
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/body_patch.py +27 -12
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/capabilities.py +1 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/data/contract_docs/support-matrix.md +4 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/document.py +35 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/errors.py +20 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/_glyph_table.py +3328 -142
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/measure.py +836 -94
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/docinfo_writer.py +4 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/header_xml.py +4 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/package.py +70 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/records.py +2 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/section_writer.py +6 -5
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/section_xml.py +69 -6
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/shape_xml.py +6 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/shapes.py +22 -16
- python_hwpx-6.9.0/src/hwpx/layout/line_cache.py +636 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/layout/lint.py +4 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/layout/pages.py +1114 -225
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/__init__.py +4 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/_document_primitives.py +30 -19
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/_paragraph_text_edit.py +5 -11
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/body.py +3 -3
- python_hwpx-6.9.0/src/hwpx/oxml/container.py +377 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/curves.py +10 -3
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/document_parts.py +38 -5
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/dutmal_compose.py +1 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/header.py +4 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/header_compat.py +6 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/header_fonts.py +75 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/memo.py +4 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/note_authoring.py +2 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/objects.py +145 -215
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/paragraph.py +54 -81
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/run.py +1 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/section.py +69 -15
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/section_format.py +185 -54
- python_hwpx-6.9.0/src/hwpx/oxml/shape_position.py +600 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/table.py +6 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/table_sizes.py +53 -1
- python_hwpx-6.9.0/src/hwpx/oxml/table_structure.py +166 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/utils.py +28 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/patch.py +11 -8
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/table_patch.py +428 -56
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/package_validator.py +27 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/toc_author.py +1 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0/src/python_hwpx.egg-info}/PKG-INFO +9 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/python_hwpx.egg-info/SOURCES.txt +22 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_authoring_defaults.py +63 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_body_patch.py +28 -0
- python_hwpx-6.9.0/tests/test_cell_edit_holder_cache.py +101 -0
- python_hwpx-6.9.0/tests/test_column_widths_as_shares.py +119 -0
- python_hwpx-6.9.0/tests/test_container_members.py +216 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_coverage_ledger.py +2 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_curve_connector_authoring.py +19 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_formatting.py +11 -4
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_metadata.py +2 -2
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_drop_cap_authoring.py +2 -2
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_dutmal_compose_authoring.py +2 -2
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_fit_hancom_rules.py +632 -5
- python_hwpx-6.9.0/tests/test_gap_and_new_number_values.py +143 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_header_compat_authoring.py +26 -0
- python_hwpx-6.9.0/tests/test_header_list_lookups.py +71 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hwp5_hancom_files.py +10 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hwp5_open.py +206 -7
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hwp5_save.py +82 -16
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_image_object_workflow.py +60 -0
- python_hwpx-6.9.0/tests/test_insert_column_by_clone.py +200 -0
- python_hwpx-6.9.0/tests/test_insert_row_sides.py +193 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_layout_cache_scope.py +95 -5
- python_hwpx-6.9.0/tests/test_layout_line_cache.py +658 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_layout_page_estimate.py +877 -22
- python_hwpx-6.9.0/tests/test_line_break_writing.py +86 -0
- python_hwpx-6.9.0/tests/test_list_level_range.py +53 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_memo_fields.py +31 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_namespace_hygiene.py +4 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_native_edit_contract.py +1 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_tables.py +21 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_oxml_modularization.py +7 -3
- python_hwpx-6.9.0/tests/test_page_and_list_values.py +161 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_property_lookup.py +32 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_section_management.py +11 -0
- python_hwpx-6.9.0/tests/test_picture_adjustments.py +256 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_product_boundary.py +4 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_release_workflow_safety.py +2 -2
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_run_choice_atom_authoring.py +7 -6
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_section_columns.py +91 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_set_column_widths_uniform_split.py +6 -5
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_shape_position_frames.py +35 -1
- python_hwpx-6.9.0/tests/test_shape_size_values.py +212 -0
- python_hwpx-6.9.0/tests/test_split_cell.py +224 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_stale_layout_cache_sweep.py +13 -1
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_style_font_border_reads.py +51 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_tab_character_writing.py +8 -4
- python_hwpx-6.9.0/tests/test_table_clone_identities.py +91 -0
- python_hwpx-6.9.0/tests/test_table_column_floor.py +119 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_label.py +2 -2
- python_hwpx-6.9.0/tests/test_table_ops_cells_without_geometry.py +61 -0
- python_hwpx-6.9.0/tests/test_table_ops_delete_every_line.py +44 -0
- python_hwpx-6.9.0/tests/test_table_ops_delete_zones.py +74 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_patch.py +15 -2
- python_hwpx-6.9.0/tests/test_table_structure_edits.py +281 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_toc_author.py +1 -1
- python_hwpx-6.8.0/src/hwpx/oxml/shape_position.py +0 -282
- python_hwpx-6.8.0/tests/test_split_cell.py +0 -112
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/LICENSE +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/NOTICE +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/setup.cfg +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/_legacy.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/_resolve.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/_units.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/headings.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/highlight.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/_base.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/fields.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/media.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/notes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/page.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/parts.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/refs.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/styles.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/text.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/ns/tracking.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/persistence.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_document/tracked.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/_moved_modules.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/data/Skeleton.hwpx +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/data/contract_docs/known-traps.md +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/data/contract_docs/mutation-semantics.md +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/data/contract_docs/recipes-traversal.md +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/eqedit.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/mathml.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/measure.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/render.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/equation/tokens.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/experimental.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/apply.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/engine.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/policy.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/form_fit/report.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/binary.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/bodytext.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/cfb.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/controls.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/docinfo.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/errors.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/fileheader.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/owpml.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/reader.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/section_common.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/summary.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/hwp5/writer.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/ingest/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/ingest/base.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/ingest/hwpx_converter.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/layout/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/layout/report.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/model.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/mutation_report.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/binary_item.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/checkbox.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/form_field.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/highlight.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/results.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/objects/tracked.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/opc/package.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/opc/relationships.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/opc/security.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/opc/xml_utils.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/_document_impl.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/canonical_defaults.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/color.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/common.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/document.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/document_metadata.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/drop_cap.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/field_marks.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/header_part.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/history_part.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/hyperlink_form.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/master_page.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/master_page_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/namespaces.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/numbering.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/numbering_kinds.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/paragraph_heading.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/parser.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/schema.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/section_layout.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/section_story.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/settings.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/simple_parts.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/table_merge.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/oxml/version_part.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/package.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/plan/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/plan/_execute.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/plan/_model.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/plan/_schema.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/plan/_validate.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/py.typed +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/ledger.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/policy.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/rendering.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/report.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/quality/save_pipeline.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/templates.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/__init__.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/header.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/owpml-body.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/owpml-core.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/owpml-header.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/owpml-paralist.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/owpml-xml.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/_schemas/section.xsd +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/archive_cli.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/doc_diff.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/document_merge.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/document_viewer.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/exporter.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/generic_inventory.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/id_integrity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/idempotence.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/ir_equality.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/layout_preview.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/mail_merge.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/markdown_export.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/object_finder.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/package_reconcile.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/page_guard.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/read_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/recover.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/redline.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/repair.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/report_utils.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/roundtrip_diff.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/table_cleanup.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/table_navigation.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/template_analyzer.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/text_extract_cli.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/text_extractor.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/toc_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/hwpx/tools/validator.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/python_hwpx.egg-info/entry_points.txt +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/python_hwpx.egg-info/requires.txt +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/src/python_hwpx.egg-info/top_level.txt +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_add_control.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_add_heading.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_adoption_metrics_snapshot.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_arc_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_authoring_quality_corpus.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_blind_eval_fixture.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_border_fill_image_gradient.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_border_line_types.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_build_element_census.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_byte_patch_identity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_capabilities_surface.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_cell_border_neighbors.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_cell_fields.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_cell_line_spacing.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_cell_margins.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_cell_text_rewrite_semantics.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_char_pr_child_order.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_character_width_ratio.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_chart_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_check_box_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_color_arguments.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_column_break.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_comment_node_robustness.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_container_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_contract_docs_sync.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_corpus_read_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_coverage_promotion.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_coverage_targets.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_deviations_registry.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_doc_diff.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_context_manager.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_facade_surface.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_merge.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_ops_runtime_boundary.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_save_api.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_document_viewer.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_documentation_code_fences.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_edit_fidelity_corpus.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_edit_plan.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_editor_surface_inventory.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_engine_surface_6_0.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equalize_widths_per_row.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_converter.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_measure_hancom_saved.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_render.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_size.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_equation_width_hancom_boxes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_error_contract.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_error_messages.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_evalplan_core_primitives.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_existing_document_format_editing.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_export_captions_dutmal.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_export_cell_text_spaces.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_export_list_labels.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_export_notes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_export_text_boxes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_exporter_table_text.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_field_marks.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_field_type_ids.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_fill_image_hancom_modes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_field_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_fields.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_fill_core_primitives.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_fit.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_form_fit_integration.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_fuzz_catalog_derive_expected.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_fuzz_loop.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_fuzz_regressions.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_gap_closure_tools.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_golden_api.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_header_control_before_field.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_heading_style_shapes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_highlight_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hp_tab_support.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hwp5_container.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hwpxlib_corpus_read.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_hyperlink_hancom_form.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_id_generator_range.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_id_integrity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_index_mark.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ingest.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_inline_models.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_insert_row_merged_cells.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_instid_attribute_case.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_integration_hwpx_compatibility.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_integration_roundtrip.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_internal_calls_skip_moved_names.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_layer_leak_guard.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_layout_lint.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_layout_preview.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_lazy_hwp5_import.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_lazy_tools_import.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_lazy_tools_submodules.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_library_boundary_closure.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_line_width_arguments.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_list_continue.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_list_defaults_vs_hancom.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_llms_txt.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_mail_merge_xlsx.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_manifest_resolve_once.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_markdown_export.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_markdown_export_shape_text.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_master_page_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_master_page_pages_taken.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_memo_and_style_editing.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_memo_shape_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_merge_cells_hancom_files.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_merge_cells_keeps_contents.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_moved_module_imports.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_moved_surface_hints.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_mutation_report.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_namespace_handling.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_namespace_normalization.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_new_features.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_note_authoring_contract.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_fields.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_media.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_notes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_page.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_refs.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_shapes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_ns_tracking.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_number_formats.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_opc_package.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_open_safety_corpus.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_outline_numbering.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_oxml_parsing.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_package_hygiene.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_packaging_license_metadata.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_packaging_py_typed.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_page_number_control.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_page_number_format.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_page_orientation.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_para_pr_dedup.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_align_distribute_space.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_border.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_format_targets.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_hyperlink_style.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_keep_together.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_margin_default_scale.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_property_version_switch.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_paragraph_remove_in_containers.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_part_hierarchy_read_models.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_polygon_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_public_artifact_hygiene.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_public_runtime_boundary.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_read_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_recover_broken_zip.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_redline_authoring.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_redline_verify.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_remove_unused_charts.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_remove_unused_images.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_repair_repack.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_replace_text_barriers.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_report_utils.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_repr_snapshots.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_return_contract.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_roundtrip_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_roundtrip_fidelity_corpus.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_row_heights.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_run_content_kinds.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_run_font_refs.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_run_style_base.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_safe_edit_example.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_save_keeps_inline_text_caches.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_save_pipeline.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_save_verifies_once.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_section_clear_body.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_section_headers.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_section_ids_order.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_section_properties_real_roundtrip.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_set_paragraph_format_keep.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_shape_geometry_contract.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_shape_open_safety_risk_check.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_shape_original_size.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_size_ratchet.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_skeleton_template_ids.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_split_merged_cell.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_stable_surface.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_story_edits_reach_control_copy.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_style_resolution.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_tab_definition_version_switch.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_cell_equalize.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_cleanup.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_navigation.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_page_flow.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_patch_dryrun.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_patch_m105.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_patch_structure_fixes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_table_split_merge.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_tables_default_border.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_template_analyzer_enrichment.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_box_fields.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_extractor_annotations.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_extractor_nested_once.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_extractor_run_choice_atoms.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_inline_elements.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_text_replace_everywhere.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_title_mark.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_toc_fidelity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_tracked_overlap_render_smoke.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_tracked_paragraph_delete_break.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validation_severity.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validator_comment_nodes.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validator_form_parameters.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validator_full_schema.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validator_hancom_open_rules.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_validator_section_ids.py +0 -0
- {python_hwpx-6.8.0 → python_hwpx-6.9.0}/tests/test_version_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-hwpx
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.9.0
|
|
4
4
|
Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 문서 라이브러리
|
|
5
5
|
Author: python-hwpx Maintainers
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -216,9 +216,14 @@ GitHub Release에 첨부되는 `py3-none-any` wheel을 문서와 함께 올리
|
|
|
216
216
|
## 알려진 제약
|
|
217
217
|
|
|
218
218
|
- `add_shape()` / `add_control()`은 저수준 탈출구라, 그대로 저장하면 한/글이
|
|
219
|
-
열지 못하는 파일이 됩니다(호출 시 경고만 나옵니다). 도형은
|
|
220
|
-
`
|
|
221
|
-
|
|
219
|
+
열지 못하는 파일이 됩니다(호출 시 경고만 나옵니다). 도형은 한/글이 요구하는 하위
|
|
220
|
+
요소까지 만드는 전용 메서드를 쓰세요: `add_line()` / `add_rectangle()` /
|
|
221
|
+
`add_ellipse()` / `add_arc()` / `add_polygon()` / `add_curve()` /
|
|
222
|
+
`add_connector()` / `add_container()`(묶음). 컨트롤은 `add_column_definition()` /
|
|
223
|
+
`add_bookmark()` / `add_hyperlink()`가 있습니다.
|
|
224
|
+
- 그림은 단순 개체 생성과 묶음 안 그림까지 지원합니다. 밝기·대비·회색조·흑백·투명도와 실선 테두리는
|
|
225
|
+
`add_picture()` 인자로 줄 수 있고(자르기는 `crop`, 그림자·빛남·부드러운 가장자리·반사는 `shadow`·`glow`·`soft_edge`·
|
|
226
|
+
`reflection`), 뒤집기·회전은 아직 지원하지 않습니다.
|
|
222
227
|
- 암호화된 HWPX와 암호·배포용 HWP는 지원하지 않습니다.
|
|
223
228
|
|
|
224
229
|
## 기여하기
|
|
@@ -165,9 +165,14 @@ GitHub Release에 첨부되는 `py3-none-any` wheel을 문서와 함께 올리
|
|
|
165
165
|
## 알려진 제약
|
|
166
166
|
|
|
167
167
|
- `add_shape()` / `add_control()`은 저수준 탈출구라, 그대로 저장하면 한/글이
|
|
168
|
-
열지 못하는 파일이 됩니다(호출 시 경고만 나옵니다). 도형은
|
|
169
|
-
`
|
|
170
|
-
|
|
168
|
+
열지 못하는 파일이 됩니다(호출 시 경고만 나옵니다). 도형은 한/글이 요구하는 하위
|
|
169
|
+
요소까지 만드는 전용 메서드를 쓰세요: `add_line()` / `add_rectangle()` /
|
|
170
|
+
`add_ellipse()` / `add_arc()` / `add_polygon()` / `add_curve()` /
|
|
171
|
+
`add_connector()` / `add_container()`(묶음). 컨트롤은 `add_column_definition()` /
|
|
172
|
+
`add_bookmark()` / `add_hyperlink()`가 있습니다.
|
|
173
|
+
- 그림은 단순 개체 생성과 묶음 안 그림까지 지원합니다. 밝기·대비·회색조·흑백·투명도와 실선 테두리는
|
|
174
|
+
`add_picture()` 인자로 줄 수 있고(자르기는 `crop`, 그림자·빛남·부드러운 가장자리·반사는 `shadow`·`glow`·`soft_edge`·
|
|
175
|
+
`reflection`), 뒤집기·회전은 아직 지원하지 않습니다.
|
|
171
176
|
- 암호화된 HWPX와 암호·배포용 HWP는 지원하지 않습니다.
|
|
172
177
|
|
|
173
178
|
## 기여하기
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-hwpx"
|
|
7
|
-
version = "6.
|
|
7
|
+
version = "6.9.0"
|
|
8
8
|
description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 문서 라이브러리"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -295,6 +295,9 @@ files = [
|
|
|
295
295
|
# Table width/height distribution (distribute cell width row by row) moved out
|
|
296
296
|
# of table.py -- born in the gate, per the WP-A rule.
|
|
297
297
|
"src/hwpx/oxml/table_sizes.py",
|
|
298
|
+
# Row and column insertion and deletion and cell splits on the table object, moved
|
|
299
|
+
# out of table.py -- born in the gate, per the WP-A rule.
|
|
300
|
+
"src/hwpx/oxml/table_structure.py",
|
|
298
301
|
# A paragraph shape's heading (outline levels 8 to 10 in Hancom's hp:switch form),
|
|
299
302
|
# written and read in one place -- born in the gate, per the WP-A rule.
|
|
300
303
|
"src/hwpx/oxml/paragraph_heading.py",
|
|
@@ -504,6 +507,9 @@ include = [
|
|
|
504
507
|
# Table width/height distribution (distribute cell width row by row) moved out
|
|
505
508
|
# of table.py -- born in the gate, per the WP-A rule.
|
|
506
509
|
"src/hwpx/oxml/table_sizes.py",
|
|
510
|
+
# Row and column insertion and deletion and cell splits on the table object, moved
|
|
511
|
+
# out of table.py -- born in the gate, per the WP-A rule.
|
|
512
|
+
"src/hwpx/oxml/table_structure.py",
|
|
507
513
|
# A paragraph shape's heading (outline levels 8 to 10 in Hancom's hp:switch form),
|
|
508
514
|
# written and read in one place -- born in the gate, per the WP-A rule.
|
|
509
515
|
"src/hwpx/oxml/paragraph_heading.py",
|
|
@@ -663,7 +663,7 @@ def add_form_field(
|
|
|
663
663
|
"""Create a click-here (누름틀) form field and return it as a :class:`FormField`.
|
|
664
664
|
|
|
665
665
|
The emitted XML follows the real-Hancom CLICKHERE contract
|
|
666
|
-
(
|
|
666
|
+
(inferred from Hancom Office 12.0.0.3288 gold documents). The
|
|
667
667
|
prompt (안내문) is materialized as a screen-only red-italic run, exactly as
|
|
668
668
|
Hancom authors it. The created field is immediately re-read through the
|
|
669
669
|
standard ``list_form_fields`` matcher — creation fails loudly if the
|
|
@@ -19,7 +19,9 @@ from ..oxml._document_primitives import NEW_NUM_KINDS
|
|
|
19
19
|
from ..oxml.namespaces import HH, HP
|
|
20
20
|
from ..oxml.numbering_kinds import ensure_numbering_levels
|
|
21
21
|
from ..oxml.objects import HwpxOxmlInlineObject
|
|
22
|
-
from ..oxml.section_format import
|
|
22
|
+
from ..oxml.section_format import (
|
|
23
|
+
_PAGE_LANDSCAPE, _PAGE_PORTRAIT, _checked, _page_orientation_value, column_shares, validate_column_gap,
|
|
24
|
+
)
|
|
23
25
|
from ..oxml.table_sizes import cell_margins_of
|
|
24
26
|
from ._units import _mm_to_hwp_units, _pt_to_hwp_units
|
|
25
27
|
|
|
@@ -512,12 +514,12 @@ def set_list_format(
|
|
|
512
514
|
suggestion="A continued list numbers on in the format of the list before it: "
|
|
513
515
|
"leave out number_format and start, or continue_list to start a new list.",
|
|
514
516
|
)
|
|
515
|
-
if level
|
|
517
|
+
if isinstance(level, bool) or not isinstance(level, int) or not 1 <= level <= 10:
|
|
516
518
|
raise HwpxValueError(
|
|
517
|
-
"level must be 1
|
|
519
|
+
f"level must be an int from 1 to 10; got {level!r}",
|
|
518
520
|
code="style-list-level-invalid",
|
|
519
|
-
context={"requested": level},
|
|
520
|
-
suggestion="
|
|
521
|
+
context={"requested": repr(level)},
|
|
522
|
+
suggestion="Hancom lists have ten levels, 1 to 10; it cannot save a document using a deeper one.",
|
|
521
523
|
)
|
|
522
524
|
if not doc._root.headers:
|
|
523
525
|
raise HwpxValueError(
|
|
@@ -525,6 +527,13 @@ def set_list_format(
|
|
|
525
527
|
code="document-header-missing",
|
|
526
528
|
suggestion="Check that this is an intact HWPX package.",
|
|
527
529
|
)
|
|
530
|
+
if start is not None and (isinstance(start, bool) or not isinstance(start, int) or not 0 <= start <= 0xFFFF):
|
|
531
|
+
raise HwpxValueError( # Hancom keeps a list's start as 16 bits unsigned (0 drawn as 1)
|
|
532
|
+
f"start must be an int from 0 to 65535; got {start!r}",
|
|
533
|
+
code="style-list-start-value",
|
|
534
|
+
context={"requested": repr(start)},
|
|
535
|
+
suggestion="Pass the number the list starts at, from 0 to 65535.",
|
|
536
|
+
)
|
|
528
537
|
|
|
529
538
|
level_specs: list[dict[str, str]] = [{} for _ in range(level)]
|
|
530
539
|
if bullet_char:
|
|
@@ -532,7 +541,7 @@ def set_list_format(
|
|
|
532
541
|
if number_format:
|
|
533
542
|
level_specs[level - 1]["format"] = str(number_format).upper()
|
|
534
543
|
if start is not None:
|
|
535
|
-
level_specs[level - 1]["start"] = str(
|
|
544
|
+
level_specs[level - 1]["start"] = str(start)
|
|
536
545
|
|
|
537
546
|
targets = _resolve_paragraph_targets(doc,
|
|
538
547
|
paragraph_index=paragraph_index,
|
|
@@ -609,6 +618,8 @@ def set_page_setup(
|
|
|
609
618
|
"""
|
|
610
619
|
|
|
611
620
|
normalized_orientation = _normalize_page_orientation(orientation)
|
|
621
|
+
if columns is not None: # the gap checked before the page or its margins change
|
|
622
|
+
validate_column_gap(_mm_to_hwp_units(float(column_gap_mm or 0)))
|
|
612
623
|
target_width_mm = width_mm
|
|
613
624
|
target_height_mm = height_mm
|
|
614
625
|
if paper_size:
|
|
@@ -633,6 +644,24 @@ def set_page_setup(
|
|
|
633
644
|
|
|
634
645
|
width = _mm_to_hwp_units(float(target_width_mm)) if target_width_mm is not None else None
|
|
635
646
|
height = _mm_to_hwp_units(float(target_height_mm)) if target_height_mm is not None else None
|
|
647
|
+
margin_source = dict(margins_mm or {})
|
|
648
|
+
margin_values = {
|
|
649
|
+
"left": margin_left_mm if margin_left_mm is not None else margin_source.get("left"),
|
|
650
|
+
"right": margin_right_mm if margin_right_mm is not None else margin_source.get("right"),
|
|
651
|
+
"top": margin_top_mm if margin_top_mm is not None else margin_source.get("top"),
|
|
652
|
+
"bottom": margin_bottom_mm if margin_bottom_mm is not None else margin_source.get("bottom"),
|
|
653
|
+
"header": header_margin_mm if header_margin_mm is not None else margin_source.get("header"),
|
|
654
|
+
"footer": footer_margin_mm if footer_margin_mm is not None else margin_source.get("footer"),
|
|
655
|
+
"gutter": gutter_mm if gutter_mm is not None else margin_source.get("gutter"),
|
|
656
|
+
}
|
|
657
|
+
hwp_margins = {
|
|
658
|
+
name: _mm_to_hwp_units(float(value))
|
|
659
|
+
for name, value in margin_values.items()
|
|
660
|
+
if value is not None
|
|
661
|
+
}
|
|
662
|
+
for name, value in (("width", width), ("height", height), *hwp_margins.items()):
|
|
663
|
+
if value is not None: # checked before the page or its margins change
|
|
664
|
+
_checked(name, value, 2**31 - 1, "page-size-value")
|
|
636
665
|
if width is not None or height is not None or normalized_orientation is not None:
|
|
637
666
|
# Call the local primitives directly rather than `doc.set_page_size`/
|
|
638
667
|
# `doc.set_page_margins`/`doc.set_columns` below — all three names
|
|
@@ -649,21 +678,6 @@ def set_page_setup(
|
|
|
649
678
|
section_index=section_index,
|
|
650
679
|
)
|
|
651
680
|
|
|
652
|
-
margin_source = dict(margins_mm or {})
|
|
653
|
-
margin_values = {
|
|
654
|
-
"left": margin_left_mm if margin_left_mm is not None else margin_source.get("left"),
|
|
655
|
-
"right": margin_right_mm if margin_right_mm is not None else margin_source.get("right"),
|
|
656
|
-
"top": margin_top_mm if margin_top_mm is not None else margin_source.get("top"),
|
|
657
|
-
"bottom": margin_bottom_mm if margin_bottom_mm is not None else margin_source.get("bottom"),
|
|
658
|
-
"header": header_margin_mm if header_margin_mm is not None else margin_source.get("header"),
|
|
659
|
-
"footer": footer_margin_mm if footer_margin_mm is not None else margin_source.get("footer"),
|
|
660
|
-
"gutter": gutter_mm if gutter_mm is not None else margin_source.get("gutter"),
|
|
661
|
-
}
|
|
662
|
-
hwp_margins = {
|
|
663
|
-
name: _mm_to_hwp_units(float(value))
|
|
664
|
-
for name, value in margin_values.items()
|
|
665
|
-
if value is not None
|
|
666
|
-
}
|
|
667
681
|
if hwp_margins:
|
|
668
682
|
set_page_margins(
|
|
669
683
|
doc,
|
|
@@ -723,15 +737,18 @@ def set_columns(
|
|
|
723
737
|
) -> HwpxOxmlInlineObject:
|
|
724
738
|
"""Set the columns of a section, or start new columns at a paragraph.
|
|
725
739
|
|
|
726
|
-
Without ``paragraph
|
|
727
|
-
``hp:colPr`` next to ``hp:secPr``) in
|
|
728
|
-
out in ``col_count`` columns. With
|
|
729
|
-
|
|
740
|
+
Without ``paragraph``, or with a section's first one, this rewrites the
|
|
741
|
+
section's own column layout (the ``hp:colPr`` next to ``hp:secPr``) in
|
|
742
|
+
place, so the whole section is laid out in ``col_count`` columns. With a
|
|
743
|
+
later ``paragraph`` it adds a column definition there, used from it on.
|
|
730
744
|
|
|
731
745
|
Args:
|
|
732
746
|
col_count: Number of columns (1–255).
|
|
733
747
|
col_type: ``NEWSPAPER``, ``BALANCED_NEWSPAPER``, or ``PARALLEL``.
|
|
734
748
|
same_gap: Gap in HWPUNIT (7200 = 1 inch).
|
|
749
|
+
column_widths: With ``same_size=False``, a ``(width, gap)`` pair per
|
|
750
|
+
column, in HWPUNIT adding up to the text width or in plain
|
|
751
|
+
proportions; Hancom keeps them as shares of 32768 of the text width.
|
|
735
752
|
separator_type: Optional column separator line type (e.g. ``SOLID``).
|
|
736
753
|
"""
|
|
737
754
|
if not 1 <= col_count <= 255:
|
|
@@ -741,6 +758,10 @@ def set_columns(
|
|
|
741
758
|
context={"requested": col_count},
|
|
742
759
|
suggestion="Use columns=1 to remove columns.",
|
|
743
760
|
)
|
|
761
|
+
if same_size:
|
|
762
|
+
validate_column_gap(same_gap) # before a paragraph is added
|
|
763
|
+
elif column_widths:
|
|
764
|
+
column_shares(column_widths) # checked before a paragraph is added too
|
|
744
765
|
if paragraph is None:
|
|
745
766
|
target_section = _resolve_section(doc, section=section, section_index=section_index)
|
|
746
767
|
ctrl = target_section.properties.set_columns(
|
|
@@ -19,6 +19,11 @@ from ..opc.relationships import (
|
|
|
19
19
|
)
|
|
20
20
|
from ..oxml import HwpxOxmlInlineObject, HwpxOxmlParagraph
|
|
21
21
|
from ..oxml.namespaces import HC, HP
|
|
22
|
+
from ..oxml.color import normalize_color
|
|
23
|
+
from ..oxml.shape_position import PictureGlow, PictureReflection, PictureShadow, validate_picture_effects
|
|
24
|
+
from ..oxml.shape_position import (
|
|
25
|
+
validate_picture_align, validate_picture_border, validate_picture_crop, validate_picture_image, validate_shape_size,
|
|
26
|
+
)
|
|
22
27
|
from ._units import _mm_to_hwp_units
|
|
23
28
|
|
|
24
29
|
if TYPE_CHECKING:
|
|
@@ -106,23 +111,35 @@ def add_picture(
|
|
|
106
111
|
width_mm: float | None = None,
|
|
107
112
|
height_mm: float | None = None,
|
|
108
113
|
align: str | None = None,
|
|
114
|
+
brightness: int = 0,
|
|
115
|
+
contrast: int = 0,
|
|
116
|
+
effect: str = "REAL_PIC",
|
|
117
|
+
alpha: int = 0,
|
|
118
|
+
line_color: str | None = None,
|
|
119
|
+
line_width: int = 33,
|
|
120
|
+
crop: tuple[int, int, int, int] | None = None,
|
|
121
|
+
shadow: PictureShadow | None = None,
|
|
122
|
+
glow: PictureGlow | None = None,
|
|
123
|
+
soft_edge: int | None = None,
|
|
124
|
+
reflection: PictureReflection | None = None,
|
|
109
125
|
para_pr_id_ref: str | int | None = None,
|
|
110
126
|
style_id_ref: str | int | None = None,
|
|
111
127
|
char_pr_id_ref: str | int | None = None,
|
|
112
128
|
run_attributes: dict[str, str] | None = None,
|
|
113
129
|
**extra_attrs: str,
|
|
114
130
|
) -> HwpxOxmlInlineObject:
|
|
115
|
-
"""Embed image data and place a picture object in a new paragraph
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
"""Embed image data and place a picture object in a new paragraph, the image adjusted and bordered as
|
|
132
|
+
:meth:`HwpxOxmlParagraph.add_picture` takes it."""
|
|
133
|
+
|
|
134
|
+
validate_picture_align(align) # before anything is stored: Hancom reads an unknown one as LEFT
|
|
135
|
+
validate_picture_image(brightness, contrast, effect, alpha) # ... and draws no other adjustment
|
|
136
|
+
validate_picture_border(line_width)
|
|
137
|
+
if line_color is not None:
|
|
138
|
+
normalize_color(line_color)
|
|
123
139
|
resolved_width = width
|
|
124
140
|
if resolved_width is None:
|
|
125
141
|
resolved_width = _mm_to_hwp_units(width_mm) if width_mm is not None else 14400
|
|
142
|
+
validate_shape_size(resolved_width, 0) # validate before aspect-ratio arithmetic too
|
|
126
143
|
|
|
127
144
|
resolved_height = height
|
|
128
145
|
if resolved_height is None:
|
|
@@ -135,6 +152,15 @@ def add_picture(
|
|
|
135
152
|
resolved_height = round(resolved_width * source_height / source_width)
|
|
136
153
|
else:
|
|
137
154
|
resolved_height = resolved_width
|
|
155
|
+
validate_shape_size(resolved_width, resolved_height) # before anything is stored too
|
|
156
|
+
validate_picture_crop(crop, resolved_width, resolved_height)
|
|
157
|
+
validate_picture_effects(shadow, glow, soft_edge, reflection)
|
|
158
|
+
|
|
159
|
+
# Call the local primitive directly rather than `doc.add_image` — that
|
|
160
|
+
# facade name moved in 6.0 (design table row 33), and going through it
|
|
161
|
+
# would fire a DeprecationWarning on every `add_picture` call even though
|
|
162
|
+
# `add_picture` itself is a kept (unmoved) root method.
|
|
163
|
+
binary_item_id_ref = str(add_image(doc, image_data, image_format))
|
|
138
164
|
|
|
139
165
|
paragraph = doc.add_paragraph(
|
|
140
166
|
"",
|
|
@@ -158,6 +184,17 @@ def add_picture(
|
|
|
158
184
|
width=resolved_width,
|
|
159
185
|
height=resolved_height,
|
|
160
186
|
align=align,
|
|
187
|
+
brightness=brightness,
|
|
188
|
+
contrast=contrast,
|
|
189
|
+
effect=effect,
|
|
190
|
+
alpha=alpha,
|
|
191
|
+
line_color=line_color,
|
|
192
|
+
line_width=line_width,
|
|
193
|
+
crop=crop,
|
|
194
|
+
shadow=shadow,
|
|
195
|
+
glow=glow,
|
|
196
|
+
soft_edge=soft_edge,
|
|
197
|
+
reflection=reflection,
|
|
161
198
|
run_attributes=run_attributes,
|
|
162
199
|
char_pr_id_ref=char_pr_id_ref,
|
|
163
200
|
)
|
|
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
8
8
|
|
|
9
9
|
from ..errors import HwpxValueError
|
|
10
10
|
|
|
11
|
-
from ..oxml._document_primitives import _object_id
|
|
11
|
+
from ..oxml._document_primitives import _clear_paragraph_layout_cache, _object_id
|
|
12
12
|
from ..oxml.namespaces import HP
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
@@ -189,6 +189,7 @@ def attach_memo_field(
|
|
|
189
189
|
"dirty": "0",
|
|
190
190
|
"zorder": order,
|
|
191
191
|
"fieldid": MEMO_FIELD_ID,
|
|
192
|
+
"metaTag": "",
|
|
192
193
|
},
|
|
193
194
|
)
|
|
194
195
|
|
|
@@ -247,6 +248,7 @@ def attach_memo_field(
|
|
|
247
248
|
|
|
248
249
|
paragraph.element.insert(0, run_begin)
|
|
249
250
|
paragraph.element.append(run_end)
|
|
251
|
+
_clear_paragraph_layout_cache(paragraph.element) # the field's controls move its text: laid out again
|
|
250
252
|
paragraph.section.mark_dirty()
|
|
251
253
|
|
|
252
254
|
return memo
|
|
@@ -345,8 +345,8 @@ class ShapesNamespace(_Namespace):
|
|
|
345
345
|
section: "int | Section | None" = None,
|
|
346
346
|
section_index: int | None = None,
|
|
347
347
|
) -> "Shape":
|
|
348
|
-
"""도형을 그룹으로 묶는다(`ContainerMember.rect`/`.ellipse`/`.polygon
|
|
349
|
-
각 부재를 그룹 로컬 좌표로 만들어 넘긴다)."""
|
|
348
|
+
"""도형을 그룹으로 묶는다(`ContainerMember.rect`/`.ellipse`/`.polygon`/`.line`/
|
|
349
|
+
`.text_box`/`.picture`/`.group`으로 각 부재를 그룹 로컬 좌표로 만들어 넘긴다)."""
|
|
350
350
|
|
|
351
351
|
from .. import shapes as _shapes
|
|
352
352
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""`doc.tables` — 표
|
|
2
|
+
"""`doc.tables` — 표 탐색·매핑·병합·구조 편집·경로 채움.
|
|
3
3
|
|
|
4
4
|
표를 **만드는** 것은 루트에 남았다(`doc.add_table` — python-docx 대응이자
|
|
5
5
|
automation 최다 사용 저작 동사 중 하나). 만든 다음에 하는 일들이 여기 모인다.
|
|
@@ -11,7 +11,7 @@ automation 최다 사용 저작 동사 중 하나). 만든 다음에 하는 일
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
-
from typing import TYPE_CHECKING, Mapping
|
|
14
|
+
from typing import TYPE_CHECKING, Iterable, Mapping, overload
|
|
15
15
|
|
|
16
16
|
from ._base import _Namespace
|
|
17
17
|
|
|
@@ -28,7 +28,7 @@ __all__ = ["TablesNamespace"]
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class TablesNamespace(_Namespace):
|
|
31
|
-
"""표
|
|
31
|
+
"""표 탐색·매핑·병합·구조 편집·경로 채움."""
|
|
32
32
|
|
|
33
33
|
__slots__ = ()
|
|
34
34
|
_path = "doc.tables"
|
|
@@ -48,6 +48,20 @@ class TablesNamespace(_Namespace):
|
|
|
48
48
|
def __iter__(self):
|
|
49
49
|
return iter(self.all)
|
|
50
50
|
|
|
51
|
+
@overload
|
|
52
|
+
def __getitem__(self, index: int) -> "Table": ...
|
|
53
|
+
|
|
54
|
+
@overload
|
|
55
|
+
def __getitem__(self, index: slice) -> list["Table"]: ...
|
|
56
|
+
|
|
57
|
+
def __getitem__(self, index: int | slice) -> "Table | list[Table]":
|
|
58
|
+
"""문서 순서의 ``index`` 번째 표(``doc.tables[0]``, ``doc.tables[-1]``, ``doc.tables[1:3]``).
|
|
59
|
+
|
|
60
|
+
``doc.tables.all[index]``와 같다. 범위 밖이면 ``IndexError``.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
return self.all[index]
|
|
64
|
+
|
|
51
65
|
def map(self) -> "TableMapResult":
|
|
52
66
|
"""모든 표의 위치·모양·헤더 미리보기를 담은 간결 지도."""
|
|
53
67
|
|
|
@@ -78,3 +92,35 @@ class TablesNamespace(_Namespace):
|
|
|
78
92
|
"""
|
|
79
93
|
|
|
80
94
|
return table.merge_cells(cell_range)
|
|
95
|
+
|
|
96
|
+
def insert_rows(
|
|
97
|
+
self, table: "Table", ref_row: int, count: int = 1, *, side: str = "below", blank: bool = False
|
|
98
|
+
) -> None:
|
|
99
|
+
"""``ref_row`` 행을 복제해 그 아래(``side="above"``면 위)에 ``count`` 행을 넣는다.
|
|
100
|
+
|
|
101
|
+
새 칸은 같은 열 기준 칸의 서식과 글을 받고, ``blank=True``면 한/글처럼 빈 문단 하나만 둔다.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
table.insert_rows(ref_row, count, side=side, blank=blank)
|
|
105
|
+
|
|
106
|
+
def insert_columns(
|
|
107
|
+
self, table: "Table", ref_col: int, count: int = 1, *, side: str = "right", blank: bool = False
|
|
108
|
+
) -> None:
|
|
109
|
+
"""``ref_col`` 열을 복제해 그 오른쪽(``side="left"``면 왼쪽)에 ``count`` 열을 넣는다(표가 넓어진다)."""
|
|
110
|
+
|
|
111
|
+
table.insert_columns(ref_col, count, side=side, blank=blank)
|
|
112
|
+
|
|
113
|
+
def delete_rows(self, table: "Table", rows: int | Iterable[int]) -> None:
|
|
114
|
+
"""행을 지운다. 모든 행은 지울 수 없다(표 삭제를 쓴다)."""
|
|
115
|
+
|
|
116
|
+
table.delete_rows(rows)
|
|
117
|
+
|
|
118
|
+
def delete_columns(self, table: "Table", cols: int | Iterable[int]) -> None:
|
|
119
|
+
"""열을 지우고 그 폭을 남은 열에 나눈다. 모든 열은 지울 수 없다."""
|
|
120
|
+
|
|
121
|
+
table.delete_columns(cols)
|
|
122
|
+
|
|
123
|
+
def split_cell(self, table: "Table", row: int, col: int, *, rows: int = 1, cols: int = 1) -> None:
|
|
124
|
+
"""(``row``, ``col``) 칸을 ``rows`` 줄 × ``cols`` 칸으로 나눈다(한/글의 셀 나누기)."""
|
|
125
|
+
|
|
126
|
+
table.split_cell(row, col, rows=rows, cols=cols)
|
|
@@ -8,7 +8,9 @@ from typing import TYPE_CHECKING, Any, Sequence, cast
|
|
|
8
8
|
from ._units import _mm_to_hwp_units
|
|
9
9
|
from ..errors import HwpxStateError, HwpxValueError
|
|
10
10
|
from ..oxml.objects import _closed_points
|
|
11
|
-
from ..oxml.shape_position import
|
|
11
|
+
from ..oxml.shape_position import (
|
|
12
|
+
validate_equation_base_unit, validate_original_size, validate_rect_ratio, validate_shape_size,
|
|
13
|
+
)
|
|
12
14
|
|
|
13
15
|
if TYPE_CHECKING:
|
|
14
16
|
from hwpx.document import HwpxDocument
|
|
@@ -265,6 +267,8 @@ def add_rectangle(
|
|
|
265
267
|
Dimensions are in HWPUNIT. *ratio* controls corner roundness
|
|
266
268
|
(0 = sharp, 50 = semicircle).
|
|
267
269
|
"""
|
|
270
|
+
validate_shape_size(width, height)
|
|
271
|
+
validate_rect_ratio(ratio)
|
|
268
272
|
validate_original_size(original_size)
|
|
269
273
|
if paragraph is None:
|
|
270
274
|
paragraph = doc.add_paragraph(
|
|
@@ -297,6 +301,7 @@ def add_ellipse(
|
|
|
297
301
|
|
|
298
302
|
Dimensions are in HWPUNIT.
|
|
299
303
|
"""
|
|
304
|
+
validate_shape_size(width, height)
|
|
300
305
|
validate_original_size(original_size)
|
|
301
306
|
if paragraph is None:
|
|
302
307
|
paragraph = doc.add_paragraph(
|
|
@@ -334,6 +339,7 @@ def add_arc(
|
|
|
334
339
|
mechanism every other shape here already uses. *arc_type* is the
|
|
335
340
|
schema's own ``NORMAL``/``PIE``/``CHORD`` passthrough.
|
|
336
341
|
"""
|
|
342
|
+
validate_shape_size(width, height)
|
|
337
343
|
if paragraph is None:
|
|
338
344
|
paragraph = doc.add_paragraph(
|
|
339
345
|
"", section=section, section_index=section_index,
|
|
@@ -461,7 +467,8 @@ def add_container(
|
|
|
461
467
|
"""Insert a group (``<hp:container>``) wrapping *members*.
|
|
462
468
|
|
|
463
469
|
Each member is built with :class:`hwpx.oxml.ContainerMember`'s
|
|
464
|
-
``rect``/``ellipse``/``polygon``
|
|
470
|
+
``rect``/``ellipse``/``polygon``/``line``/``text_box``/``picture``/``group``
|
|
471
|
+
classmethods, which take the member's
|
|
465
472
|
position in the group's own local coordinate space (HWPUNIT, top-left
|
|
466
473
|
anchored) alongside its usual shape parameters::
|
|
467
474
|
|
|
@@ -522,15 +529,16 @@ def add_equation(
|
|
|
522
529
|
context={"length": len(text), "limit": MAX_SOURCE_LENGTH},
|
|
523
530
|
suggestion="Split the equation.",
|
|
524
531
|
)
|
|
532
|
+
validate_equation_base_unit(base_unit)
|
|
533
|
+
width, height = size if size is not None else estimate_equation_size(text, base_unit=base_unit)
|
|
534
|
+
validate_shape_size(width, height) # one measured at a huge base_unit too
|
|
525
535
|
if paragraph is None:
|
|
526
536
|
paragraph = doc.add_paragraph(
|
|
527
537
|
"", section=section, section_index=section_index,
|
|
528
538
|
include_run=False,
|
|
529
539
|
)
|
|
530
|
-
if size is None:
|
|
531
|
-
size = estimate_equation_size(text, base_unit=base_unit)
|
|
532
540
|
inline_object = paragraph.add_equation(
|
|
533
|
-
text, base_unit=base_unit, size=
|
|
541
|
+
text, base_unit=base_unit, size=(width, height), char_pr_id_ref=char_pr_id_ref,
|
|
534
542
|
)
|
|
535
543
|
|
|
536
544
|
created_id = inline_object.element.get("id", "")
|
|
@@ -756,10 +764,10 @@ def add_drop_cap(
|
|
|
756
764
|
char_pr_id_ref: str | int | None = None,
|
|
757
765
|
para_pr_id_ref: str | int | None = None,
|
|
758
766
|
) -> HwpxOxmlInlineObject:
|
|
759
|
-
"""Insert a drop cap (문단 첫 글자 장식),
|
|
767
|
+
"""Insert a drop cap (문단 첫 글자 장식), inferred from the one
|
|
760
768
|
real-corpus example that carries a non-default ``dropcapstyle``
|
|
761
769
|
(``error__20230809__test.hwpx`` -- see ``oxml.drop_cap``'s own
|
|
762
|
-
docstring for the full structural
|
|
770
|
+
docstring for the full structural format inference and why it
|
|
763
771
|
supports ``style="TripleLine"`` and ``"DoubleLine"`` only).
|
|
764
772
|
|
|
765
773
|
Element construction (element-building validation included) happens in
|
|
@@ -38,6 +38,7 @@ from typing import Any, Mapping, Sequence
|
|
|
38
38
|
from .opc.security import guard_zip_file, read_member
|
|
39
39
|
from .mutation_report import MutationReport, project_byte_splice
|
|
40
40
|
from .patch import (
|
|
41
|
+
_escaped_text,
|
|
41
42
|
_finalize,
|
|
42
43
|
_patch_zip_entries,
|
|
43
44
|
_read_source_bytes,
|
|
@@ -185,9 +186,9 @@ def _op_replace_text(xml: str, op: Mapping[str, Any]) -> tuple[str, dict[str, An
|
|
|
185
186
|
replace = str(op.get("replace", ""))
|
|
186
187
|
expected = int(op.get("count", 1))
|
|
187
188
|
esc_find = html.escape(find, quote=False)
|
|
188
|
-
# A tab goes in as an hp:tab element
|
|
189
|
-
# raw tab character inside hp:t.
|
|
190
|
-
esc_replace = "
|
|
189
|
+
# A tab goes in as an hp:tab element (Hancom never finishes laying out a
|
|
190
|
+
# raw tab character inside hp:t), a line break as an hp:lineBreak.
|
|
191
|
+
esc_replace = _escaped_text(replace, b"hp:").decode("utf-8")
|
|
191
192
|
hits: list[tuple[int, int]] = []
|
|
192
193
|
for t in _T_CONTENT_RE.finditer(xml):
|
|
193
194
|
a, b = t.start(1), t.end(1)
|
|
@@ -215,14 +216,6 @@ def _op_replace_text(xml: str, op: Mapping[str, Any]) -> tuple[str, dict[str, An
|
|
|
215
216
|
raise ValueError("replace_text: match outside any <hp:p> paragraph")
|
|
216
217
|
by_para.setdefault(span, []).append(hit)
|
|
217
218
|
|
|
218
|
-
edits: list[tuple[int, int, str]] = []
|
|
219
|
-
for (pa, pb), phits in by_para.items():
|
|
220
|
-
block = xml[pa:pb]
|
|
221
|
-
for a, b in sorted(phits, reverse=True):
|
|
222
|
-
block = block[: a - pa] + esc_replace + block[b - pa:]
|
|
223
|
-
block = _strip_paragraph_layout_cache(block.encode("utf-8")).decode("utf-8")
|
|
224
|
-
edits.append((pa, pb, block))
|
|
225
|
-
|
|
226
219
|
# 모듈 취지는 표-밖 본문이지만(위 docstring), <hp:t> 검색은 구조적으로
|
|
227
220
|
# 표 셀 내부까지 닿는다 — 편집된 문단이 셀(subList) 안이면 그 셀의
|
|
228
221
|
# lineWrap=SQUEEZE도 함께 BREAK로 바꾼다. 안 바꾸면 실측대로 압축 자간이
|
|
@@ -232,6 +225,7 @@ def _op_replace_text(xml: str, op: Mapping[str, Any]) -> tuple[str, dict[str, An
|
|
|
232
225
|
# 문단이 여럿이어도 셀 편집은 한 번만.
|
|
233
226
|
sublist_spans = _all_sublist_spans(xml)
|
|
234
227
|
fixed_sublists: set[tuple[int, int]] = set()
|
|
228
|
+
wrap_edits: list[tuple[int, int, str]] = []
|
|
235
229
|
for pa, _pb in by_para:
|
|
236
230
|
sublist_span = _innermost_span(pa, sublist_spans)
|
|
237
231
|
if sublist_span is None or sublist_span in fixed_sublists:
|
|
@@ -239,7 +233,28 @@ def _op_replace_text(xml: str, op: Mapping[str, Any]) -> tuple[str, dict[str, An
|
|
|
239
233
|
fixed_sublists.add(sublist_span)
|
|
240
234
|
wrap_edit = _squeeze_wrap_edit_for_sublist(xml, sublist_span)
|
|
241
235
|
if wrap_edit is not None:
|
|
242
|
-
|
|
236
|
+
wrap_edits.append(wrap_edit)
|
|
237
|
+
|
|
238
|
+
# 표를 담은 문단과 그 표의 셀 문단이 둘 다 편집되면 두 문단 구간이 겹친다.
|
|
239
|
+
# 바깥 문단 하나로 묶어 그 안의 치환·셀 SQUEEZE 편집을 한 번에 적용한 뒤
|
|
240
|
+
# 캐시를 지운다(바깥 문단의 캐시 제거가 안쪽 문단의 캐시도 지운다).
|
|
241
|
+
outer = [
|
|
242
|
+
span for span in by_para
|
|
243
|
+
if not any(other != span and other[0] <= span[0] and span[1] <= other[1] for other in by_para)
|
|
244
|
+
]
|
|
245
|
+
edits: list[tuple[int, int, str]] = []
|
|
246
|
+
for pa, pb in outer:
|
|
247
|
+
local = [(a, b, esc_replace) for a, b in hits if pa <= a < pb]
|
|
248
|
+
local += [edit for edit in wrap_edits if pa <= edit[0] and edit[1] <= pb]
|
|
249
|
+
block = xml[pa:pb]
|
|
250
|
+
for a, b, replacement in sorted(local, key=lambda e: e[0], reverse=True):
|
|
251
|
+
block = block[: a - pa] + replacement + block[b - pa:]
|
|
252
|
+
block = _strip_paragraph_layout_cache(block.encode("utf-8")).decode("utf-8")
|
|
253
|
+
edits.append((pa, pb, block))
|
|
254
|
+
edits += [
|
|
255
|
+
edit for edit in wrap_edits
|
|
256
|
+
if not any(pa <= edit[0] and edit[1] <= pb for pa, pb in outer)
|
|
257
|
+
]
|
|
243
258
|
|
|
244
259
|
for a, b, replacement in sorted(edits, key=lambda e: e[0], reverse=True):
|
|
245
260
|
xml = xml[:a] + replacement + xml[b:]
|
|
@@ -81,7 +81,7 @@ _CAPABILITY_AREAS: tuple[dict[str, Any], ...] = (
|
|
|
81
81
|
"area": "table-structure",
|
|
82
82
|
"namespace": "doc.tables",
|
|
83
83
|
"matrix_row": "표 구조 변경(행·열·표 삭제/삽입, 열 오토핏)",
|
|
84
|
-
"entry_points": ("hwpx.table_patch:apply_table_ops",),
|
|
84
|
+
"entry_points": ("hwpx.table_patch:apply_table_ops", "hwpx.model:Table"),
|
|
85
85
|
"authoring_methods": (),
|
|
86
86
|
},
|
|
87
87
|
{
|