python-hwpx 6.0.3__tar.gz → 6.2.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.
- {python_hwpx-6.0.3/src/python_hwpx.egg-info → python_hwpx-6.2.1}/PKG-INFO +1 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/pyproject.toml +141 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/_legacy.py +16 -1
- python_hwpx-6.2.1/src/hwpx/_document/highlight.py +164 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/layout.py +128 -11
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/__init__.py +1 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/page.py +125 -1
- python_hwpx-6.2.1/src/hwpx/_document/ns/parts.py +274 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/shapes.py +182 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/styles.py +269 -4
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/text.py +30 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/shapes.py +244 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/capabilities.py +273 -2
- python_hwpx-6.2.1/src/hwpx/data/contract_docs/support-matrix.md +137 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/errors.py +59 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/__init__.py +2 -0
- python_hwpx-6.2.1/src/hwpx/objects/highlight.py +41 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/opc/package.py +123 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/opc/relationships.py +6 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/__init__.py +46 -2
- python_hwpx-6.2.1/src/hwpx/oxml/_document_primitives.py +1565 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/body.py +488 -0
- python_hwpx-6.2.1/src/hwpx/oxml/document_metadata.py +94 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/document_parts.py +321 -106
- python_hwpx-6.2.1/src/hwpx/oxml/drop_cap.py +218 -0
- python_hwpx-6.2.1/src/hwpx/oxml/dutmal_compose.py +125 -0
- python_hwpx-6.2.1/src/hwpx/oxml/field_marks.py +409 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/header.py +349 -4
- python_hwpx-6.2.1/src/hwpx/oxml/header_compat.py +317 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/header_part.py +260 -123
- python_hwpx-6.2.1/src/hwpx/oxml/history_part.py +162 -0
- python_hwpx-6.2.1/src/hwpx/oxml/master_page.py +104 -0
- python_hwpx-6.2.1/src/hwpx/oxml/master_page_authoring.py +153 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/namespaces.py +8 -0
- python_hwpx-6.2.1/src/hwpx/oxml/note_authoring.py +193 -0
- python_hwpx-6.2.1/src/hwpx/oxml/numbering_kinds.py +98 -0
- python_hwpx-6.2.1/src/hwpx/oxml/objects.py +1526 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/paragraph.py +325 -281
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/run.py +23 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/section_format.py +79 -0
- python_hwpx-6.2.1/src/hwpx/oxml/section_layout.py +133 -0
- python_hwpx-6.2.1/src/hwpx/oxml/settings.py +155 -0
- python_hwpx-6.2.1/src/hwpx/oxml/simple_parts.py +123 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/table.py +253 -0
- python_hwpx-6.2.1/src/hwpx/oxml/version_part.py +68 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/table_patch.py +229 -30
- python_hwpx-6.2.1/src/hwpx/tools/document_merge.py +1306 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/id_integrity.py +15 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/mail_merge.py +2 -2
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/markdown_export.py +25 -2
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/package_validator.py +83 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/text_extractor.py +31 -2
- {python_hwpx-6.0.3 → python_hwpx-6.2.1/src/python_hwpx.egg-info}/PKG-INFO +1 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/python_hwpx.egg-info/SOURCES.txt +47 -0
- python_hwpx-6.2.1/tests/test_arc_authoring.py +294 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_authoring_defaults.py +101 -0
- python_hwpx-6.2.1/tests/test_border_fill_image_gradient.py +361 -0
- python_hwpx-6.2.1/tests/test_build_element_census.py +186 -0
- python_hwpx-6.2.1/tests/test_column_break.py +109 -0
- python_hwpx-6.2.1/tests/test_container_authoring.py +313 -0
- python_hwpx-6.2.1/tests/test_coverage_ledger.py +1056 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_coverage_promotion.py +267 -0
- python_hwpx-6.2.1/tests/test_deviations_registry.py +454 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_formatting.py +743 -0
- python_hwpx-6.2.1/tests/test_document_merge.py +1149 -0
- python_hwpx-6.2.1/tests/test_document_metadata.py +141 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_ops_runtime_boundary.py +52 -0
- python_hwpx-6.2.1/tests/test_drop_cap_authoring.py +141 -0
- python_hwpx-6.2.1/tests/test_dutmal_compose_authoring.py +209 -0
- python_hwpx-6.2.1/tests/test_editor_surface_inventory.py +119 -0
- python_hwpx-6.2.1/tests/test_field_marks.py +328 -0
- python_hwpx-6.2.1/tests/test_header_compat_authoring.py +293 -0
- python_hwpx-6.2.1/tests/test_highlight_authoring.py +289 -0
- python_hwpx-6.2.1/tests/test_id_integrity.py +54 -0
- python_hwpx-6.2.1/tests/test_index_mark.py +158 -0
- python_hwpx-6.2.1/tests/test_master_page_authoring.py +170 -0
- python_hwpx-6.2.1/tests/test_memo_shape_authoring.py +249 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_namespace_hygiene.py +36 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_page.py +47 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_refs.py +13 -4
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_shapes.py +2 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_opc_package.py +49 -0
- python_hwpx-6.2.1/tests/test_outline_numbering.py +120 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_oxml_modularization.py +45 -1
- python_hwpx-6.2.1/tests/test_page_number_control.py +294 -0
- python_hwpx-6.2.1/tests/test_para_pr_dedup.py +132 -0
- python_hwpx-6.2.1/tests/test_paragraph_property_version_switch.py +160 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_paragraph_section_management.py +29 -0
- python_hwpx-6.2.1/tests/test_part_hierarchy_read_models.py +250 -0
- python_hwpx-6.2.1/tests/test_polygon_authoring.py +354 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_product_boundary.py +45 -1
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_redline_authoring.py +62 -0
- python_hwpx-6.2.1/tests/test_run_choice_atom_authoring.py +175 -0
- python_hwpx-6.2.1/tests/test_shape_open_safety_risk_check.py +156 -0
- python_hwpx-6.2.1/tests/test_tab_definition_version_switch.py +189 -0
- python_hwpx-6.2.1/tests/test_table_cell_equalize.py +92 -0
- python_hwpx-6.2.1/tests/test_table_label.py +150 -0
- python_hwpx-6.2.1/tests/test_table_split_merge.py +258 -0
- python_hwpx-6.2.1/tests/test_text_extractor_run_choice_atoms.py +160 -0
- python_hwpx-6.2.1/tests/test_title_mark.py +133 -0
- python_hwpx-6.0.3/src/hwpx/_document/ns/parts.py +0 -68
- python_hwpx-6.0.3/src/hwpx/data/contract_docs/support-matrix.md +0 -93
- python_hwpx-6.0.3/src/hwpx/oxml/_document_primitives.py +0 -696
- python_hwpx-6.0.3/src/hwpx/oxml/objects.py +0 -596
- python_hwpx-6.0.3/src/hwpx/oxml/simple_parts.py +0 -69
- python_hwpx-6.0.3/tests/test_coverage_ledger.py +0 -414
- python_hwpx-6.0.3/tests/test_deviations_registry.py +0 -12
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/LICENSE +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/NOTICE +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/README.md +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/setup.cfg +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/_resolve.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/_units.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/fields.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/headings.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/media.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/memos.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/_base.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/fields.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/media.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/notes.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/refs.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/tables.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/ns/tracking.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/persistence.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/_document/tracked.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/body_patch.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/data/Skeleton.hwpx +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/data/contract_docs/known-traps.md +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/data/contract_docs/mutation-semantics.md +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/data/contract_docs/recipes-traversal.md +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/document.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/authoring.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/eqedit.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/mathml.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/render.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/equation/tokens.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/experimental.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/apply.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/engine.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/measure.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/policy.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/form_fit/report.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/ingest/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/ingest/base.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/ingest/hwpx_converter.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/layout/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/layout/lint.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/layout/report.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/model.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/mutation_report.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/binary_item.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/checkbox.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/form_field.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/results.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/objects/tracked.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/opc/security.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/opc/xml_utils.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/_document_impl.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/canonical_defaults.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/color.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/common.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/document.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/memo.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/numbering.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/parser.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/schema.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/section.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/section_story.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/oxml/utils.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/package.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/patch.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/plan/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/plan/_execute.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/plan/_model.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/plan/_schema.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/plan/_validate.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/py.typed +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/ledger.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/policy.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/rendering.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/report.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/quality/save_pipeline.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/templates.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/__init__.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/_schemas/header.xsd +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/_schemas/section.xsd +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/archive_cli.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/doc_diff.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/document_viewer.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/exporter.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/generic_inventory.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/idempotence.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/ir_equality.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/layout_preview.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/object_finder.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/package_reconcile.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/page_guard.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/read_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/recover.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/redline.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/repair.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/report_utils.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/roundtrip_diff.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/table_cleanup.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/table_navigation.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/template_analyzer.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/text_extract_cli.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/toc_author.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/toc_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/hwpx/tools/validator.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/python_hwpx.egg-info/entry_points.txt +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/python_hwpx.egg-info/requires.txt +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/src/python_hwpx.egg-info/top_level.txt +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_add_control.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_add_heading.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_adoption_metrics_snapshot.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_authoring_quality_corpus.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_blind_eval_fixture.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_body_patch.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_byte_patch_identity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_capabilities_surface.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_cell_line_spacing.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_chart_authoring.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_check_box_authoring.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_comment_node_robustness.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_contract_docs_sync.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_corpus_read_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_coverage_targets.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_doc_diff.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_context_manager.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_facade_surface.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_save_api.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_document_viewer.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_documentation_code_fences.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_edit_plan.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_engine_surface_6_0.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_equation_authoring.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_equation_converter.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_equation_render.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_error_contract.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_error_messages.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_evalplan_core_primitives.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_existing_document_format_editing.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_form_field_authoring.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_form_fields.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_form_fill_core_primitives.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_form_fit.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_form_fit_integration.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_fuzz_catalog_derive_expected.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_fuzz_loop.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_fuzz_regressions.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_gap_closure_tools.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_golden_api.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_hp_tab_support.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_hwpxlib_corpus_read.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_id_generator_range.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_image_object_workflow.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ingest.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_inline_models.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_integration_hwpx_compatibility.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_integration_roundtrip.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_layout_cache_scope.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_layout_lint.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_layout_preview.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_library_boundary_closure.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_llms_txt.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_mail_merge_xlsx.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_markdown_export.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_memo_and_style_editing.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_moved_surface_hints.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_mutation_report.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_namespace_handling.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_new_features.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_note_authoring_contract.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_fields.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_media.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_notes.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_tables.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_ns_tracking.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_open_safety_corpus.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_oxml_parsing.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_packaging_license_metadata.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_packaging_py_typed.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_paragraph_keep_together.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_public_artifact_hygiene.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_public_runtime_boundary.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_read_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_recover_broken_zip.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_redline_verify.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_release_workflow_safety.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_repair_repack.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_report_utils.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_repr_snapshots.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_return_contract.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_roundtrip_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_row_heights.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_save_pipeline.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_section_headers.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_section_properties_real_roundtrip.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_set_paragraph_format_keep.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_shape_geometry_contract.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_skeleton_template_ids.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_split_cell.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_split_merged_cell.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_stable_surface.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_style_resolution.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_table_cleanup.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_table_navigation.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_table_patch.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_table_patch_dryrun.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_table_patch_m105.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_tables_default_border.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_template_analyzer_enrichment.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_text_extractor_annotations.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_toc_author.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_toc_fidelity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_validation_severity.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_validator_comment_nodes.py +0 -0
- {python_hwpx-6.0.3 → python_hwpx-6.2.1}/tests/test_version_metadata.py +0 -0
|
@@ -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.2.1"
|
|
8
8
|
description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 문서 라이브러리"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -153,6 +153,15 @@ files = [
|
|
|
153
153
|
"src/hwpx/errors.py",
|
|
154
154
|
"src/hwpx/mutation_report.py",
|
|
155
155
|
"src/hwpx/capabilities.py",
|
|
156
|
+
# 6.14 트레인㊾-1 — pre-existing 49 errors 정리 후 편입(6.12 이전부터의
|
|
157
|
+
# 기존 부채, f7e4e67 리뷰가 지목). 대부분 _si()가 돌려주는 int|None을
|
|
158
|
+
# 산술/비교에 바로 쓰던 자리(스키마상 필수 hp:tc 속성이라 실제로는
|
|
159
|
+
# None일 수 없음 -- assert로 좁힘) + 한 함수 안에서 변수 이름을
|
|
160
|
+
# re.Match와 int 양쪽으로 재사용하던 자리(이름만 갈라 해소, 동작
|
|
161
|
+
# 불변) + 람다 기본인자가 오버로드 추론을 깨던 자리(named 중첩
|
|
162
|
+
# 함수로 치환). 동작 변경 없음(assert 실패는 이전에도 TypeError로
|
|
163
|
+
# 이미 죽던 자리를 더 명확한 메시지로 바꾼 것뿐).
|
|
164
|
+
"src/hwpx/table_patch.py",
|
|
156
165
|
"src/hwpx/plan/__init__.py",
|
|
157
166
|
"src/hwpx/plan/_model.py",
|
|
158
167
|
"src/hwpx/plan/_validate.py",
|
|
@@ -187,8 +196,10 @@ files = [
|
|
|
187
196
|
"src/hwpx/objects/form_field.py",
|
|
188
197
|
"src/hwpx/objects/results.py",
|
|
189
198
|
"src/hwpx/objects/tracked.py",
|
|
199
|
+
"src/hwpx/objects/highlight.py",
|
|
190
200
|
"src/hwpx/_document/_resolve.py",
|
|
191
201
|
"src/hwpx/_document/headings.py",
|
|
202
|
+
"src/hwpx/_document/highlight.py",
|
|
192
203
|
"src/hwpx/_document/ns",
|
|
193
204
|
"src/hwpx/_document/fields.py",
|
|
194
205
|
"src/hwpx/_document/layout.py",
|
|
@@ -225,7 +236,79 @@ files = [
|
|
|
225
236
|
"src/hwpx/tools/text_extractor.py",
|
|
226
237
|
"tests/template_automation/helpers.py",
|
|
227
238
|
"tests/template_automation/generate_fixtures.py",
|
|
239
|
+
# 6.4: part-hierarchy read models (gap #15) — born in the gate, per the
|
|
240
|
+
# WP-A rule above.
|
|
241
|
+
"src/hwpx/oxml/version_part.py",
|
|
242
|
+
"src/hwpx/oxml/master_page.py",
|
|
243
|
+
"src/hwpx/oxml/history_part.py",
|
|
244
|
+
# 6.6 (train 23): document options/compatibility authoring — born in the
|
|
245
|
+
# gate, per the WP-A rule above.
|
|
246
|
+
"src/hwpx/oxml/header_compat.py",
|
|
247
|
+
# 6.9 (train 33): document insertion/merge — born in the gate, per the
|
|
248
|
+
# WP-A rule above.
|
|
249
|
+
"src/hwpx/tools/document_merge.py",
|
|
250
|
+
# 6.9 (train 34): dutmal/compose authoring — born in the gate, per the
|
|
251
|
+
# WP-A rule above.
|
|
252
|
+
"src/hwpx/oxml/dutmal_compose.py",
|
|
253
|
+
# 6.11 (train 44): add_section() layout-carrier lookup, extracted from
|
|
254
|
+
# document_parts.py (1600-line cap) — born in the gate, per the WP-A
|
|
255
|
+
# rule above.
|
|
256
|
+
"src/hwpx/oxml/section_layout.py",
|
|
257
|
+
# 6.12 (train 48): opf:metadata (content.hpf document properties) read
|
|
258
|
+
# model — born in the gate, per the WP-A rule above.
|
|
259
|
+
"src/hwpx/oxml/document_metadata.py",
|
|
260
|
+
# 6.12 (train 48): drop cap (hp:rect dropcapstyle) shape-authoring
|
|
261
|
+
# overflow module, extracted from paragraph.py (1600-line cap) — born
|
|
262
|
+
# in the gate, per the WP-A rule above.
|
|
263
|
+
"src/hwpx/oxml/drop_cap.py",
|
|
264
|
+
# 6.13 (train 48): ensure_numbering's full body (bullet/number/outline
|
|
265
|
+
# kinds), moved out of header_part.py (1600-line cap, no headroom left
|
|
266
|
+
# once the new "outline" kind was added) — born in the gate, per the
|
|
267
|
+
# WP-A rule above.
|
|
268
|
+
"src/hwpx/oxml/numbering_kinds.py",
|
|
269
|
+
# 6.13 (train 48): master page (바탕쪽) part creation + manifest
|
|
270
|
+
# registration — new module from the start (document_parts.py had
|
|
271
|
+
# modest headroom but this needed more than fit safely), per the WP-A
|
|
272
|
+
# rule above.
|
|
273
|
+
"src/hwpx/oxml/master_page_authoring.py",
|
|
274
|
+
# 6.13 (train 48): date field (hp:fieldBegin type=DATE) + proofreading
|
|
275
|
+
# mark field (type=PROOFREADING_MARKS_SIGN) authoring — new module
|
|
276
|
+
# from the start; paragraph.py hit exactly 1600 lines with just the
|
|
277
|
+
# two delegator methods (zero headroom left, resolved by the
|
|
278
|
+
# extraction below), per the WP-A rule above.
|
|
279
|
+
"src/hwpx/oxml/field_marks.py",
|
|
280
|
+
# 6.14 (train 48/debt3): footnote/endnote (각주/미주) authoring moved
|
|
281
|
+
# out of paragraph.py verbatim (no behavior change) to restore real
|
|
282
|
+
# headroom -- same escape valve as dutmal_compose.py/objects.py/
|
|
283
|
+
# field_marks.py above, per the WP-A rule.
|
|
284
|
+
"src/hwpx/oxml/note_authoring.py",
|
|
228
285
|
]
|
|
286
|
+
# 칩 후보 1 ✅ 6.14 트레인㊾-1에서 해소: `src/hwpx/table_patch.py`(2073줄,
|
|
287
|
+
# 6.12 트레인㊸ 갭⑤ 정리 시 team-lead가 지목, f7e4e67 리뷰) — 위 files
|
|
288
|
+
# 리스트에 이미 편입돼 있다(pre-existing 49 errors 정리, 이 섹션 첫
|
|
289
|
+
# 항목 주석 참조). 이 블록 자체는 이력으로 남긴다.
|
|
290
|
+
#
|
|
291
|
+
# 다음 사이클 칩 후보 2(6.13 트레인㊼, titleMark 재프로브 부산물로
|
|
292
|
+
# team-lead가 지목): `HwpxDocument.add_heading`(document.py) →
|
|
293
|
+
# `_headings.bind_outline_level` → `_document/layout.py`의
|
|
294
|
+
# `set_paragraph_format(outline_level=)`이 호출될 때마다 **동일한
|
|
295
|
+
# paraPr이 이미 있어도 새 id로 다시 만든다**(기존 요소 재사용/dedup
|
|
296
|
+
# 조회 없음) — 실한컴은 저장 시점에 중복 paraPr을 자기가 병합한다
|
|
297
|
+
# (titleMark 재프로브에서 paraPrIDRef가 21→20으로 "되돌아간" 현상의
|
|
298
|
+
# 원인, 버그 아님·관측된 실동작으로 문서화됨). 우리 쪽에서 paraPr
|
|
299
|
+
# 재사용 lookup을 추가하면 왕복 시 이 되돌아감이 사라지고 저장 파일도
|
|
300
|
+
# 더 작아진다 — fix 안 함, 스코프 밖.
|
|
301
|
+
#
|
|
302
|
+
# 다음 사이클 칩 후보 3(6.13 트레인㊼): `src/hwpx/oxml/paragraph.py`가
|
|
303
|
+
# `add_date_field`/`add_proofreading_mark` 두 delegator를 추가하며
|
|
304
|
+
# 정확히 1600줄(WP-A owner-file 캡)을 채웠다 — 헤드룸 0. 다음에 이
|
|
305
|
+
# 파일에 뭔가 더 추가해야 하면(신규 필드류 저작 등) 곧바로 게이트가
|
|
306
|
+
# 막는다 — 실제 추출/재구조화 패스가 필요하다(어디를 오버플로 모듈로
|
|
307
|
+
# 뺄지는 이번 트레인에서 정하지 않음, 다음 트레인의 몫).
|
|
308
|
+
#
|
|
309
|
+
# 위 세 칩(table_patch 게이트 미편입·add_heading paraPr 비-dedup·
|
|
310
|
+
# paragraph.py 헤드룸 0)은 다음 사이클 초입 부채상환 트레인 후보로
|
|
311
|
+
# 함께 묶어 처리할 것 — team-lead 지시(6.13 트레인㊼ 정리 커밋).
|
|
229
312
|
ignore_missing_imports = true
|
|
230
313
|
|
|
231
314
|
[tool.pyright]
|
|
@@ -236,6 +319,15 @@ include = [
|
|
|
236
319
|
"src/hwpx/errors.py",
|
|
237
320
|
"src/hwpx/mutation_report.py",
|
|
238
321
|
"src/hwpx/capabilities.py",
|
|
322
|
+
# 6.14 트레인㊾-1 — pre-existing 49 errors 정리 후 편입(6.12 이전부터의
|
|
323
|
+
# 기존 부채, f7e4e67 리뷰가 지목). 대부분 _si()가 돌려주는 int|None을
|
|
324
|
+
# 산술/비교에 바로 쓰던 자리(스키마상 필수 hp:tc 속성이라 실제로는
|
|
325
|
+
# None일 수 없음 -- assert로 좁힘) + 한 함수 안에서 변수 이름을
|
|
326
|
+
# re.Match와 int 양쪽으로 재사용하던 자리(이름만 갈라 해소, 동작
|
|
327
|
+
# 불변) + 람다 기본인자가 오버로드 추론을 깨던 자리(named 중첩
|
|
328
|
+
# 함수로 치환). 동작 변경 없음(assert 실패는 이전에도 TypeError로
|
|
329
|
+
# 이미 죽던 자리를 더 명확한 메시지로 바꾼 것뿐).
|
|
330
|
+
"src/hwpx/table_patch.py",
|
|
239
331
|
"src/hwpx/plan/__init__.py",
|
|
240
332
|
"src/hwpx/plan/_model.py",
|
|
241
333
|
"src/hwpx/plan/_validate.py",
|
|
@@ -270,8 +362,10 @@ include = [
|
|
|
270
362
|
"src/hwpx/objects/form_field.py",
|
|
271
363
|
"src/hwpx/objects/results.py",
|
|
272
364
|
"src/hwpx/objects/tracked.py",
|
|
365
|
+
"src/hwpx/objects/highlight.py",
|
|
273
366
|
"src/hwpx/_document/_resolve.py",
|
|
274
367
|
"src/hwpx/_document/headings.py",
|
|
368
|
+
"src/hwpx/_document/highlight.py",
|
|
275
369
|
"src/hwpx/_document/ns",
|
|
276
370
|
"src/hwpx/_document/fields.py",
|
|
277
371
|
"src/hwpx/_document/layout.py",
|
|
@@ -308,6 +402,52 @@ include = [
|
|
|
308
402
|
"src/hwpx/tools/text_extractor.py",
|
|
309
403
|
"tests/template_automation/helpers.py",
|
|
310
404
|
"tests/template_automation/generate_fixtures.py",
|
|
405
|
+
# 6.4: part-hierarchy read models (gap #15) — born in the gate, per the
|
|
406
|
+
# WP-A rule above.
|
|
407
|
+
"src/hwpx/oxml/version_part.py",
|
|
408
|
+
"src/hwpx/oxml/master_page.py",
|
|
409
|
+
"src/hwpx/oxml/history_part.py",
|
|
410
|
+
# 6.6 (train 23): document options/compatibility authoring — born in the
|
|
411
|
+
# gate, per the WP-A rule above.
|
|
412
|
+
"src/hwpx/oxml/header_compat.py",
|
|
413
|
+
# 6.9 (train 33): document insertion/merge — born in the gate, per the
|
|
414
|
+
# WP-A rule above.
|
|
415
|
+
"src/hwpx/tools/document_merge.py",
|
|
416
|
+
# 6.9 (train 34): dutmal/compose authoring — born in the gate, per the
|
|
417
|
+
# WP-A rule above.
|
|
418
|
+
"src/hwpx/oxml/dutmal_compose.py",
|
|
419
|
+
# 6.11 (train 44): add_section() layout-carrier lookup, extracted from
|
|
420
|
+
# document_parts.py (1600-line cap) — born in the gate, per the WP-A
|
|
421
|
+
# rule above.
|
|
422
|
+
"src/hwpx/oxml/section_layout.py",
|
|
423
|
+
# 6.12 (train 48): opf:metadata (content.hpf document properties) read
|
|
424
|
+
# model — born in the gate, per the WP-A rule above.
|
|
425
|
+
"src/hwpx/oxml/document_metadata.py",
|
|
426
|
+
# 6.12 (train 48): drop cap (hp:rect dropcapstyle) shape-authoring
|
|
427
|
+
# overflow module, extracted from paragraph.py (1600-line cap) — born
|
|
428
|
+
# in the gate, per the WP-A rule above.
|
|
429
|
+
"src/hwpx/oxml/drop_cap.py",
|
|
430
|
+
# 6.13 (train 48): ensure_numbering's full body (bullet/number/outline
|
|
431
|
+
# kinds), moved out of header_part.py (1600-line cap, no headroom left
|
|
432
|
+
# once the new "outline" kind was added) — born in the gate, per the
|
|
433
|
+
# WP-A rule above.
|
|
434
|
+
"src/hwpx/oxml/numbering_kinds.py",
|
|
435
|
+
# 6.13 (train 48): master page (바탕쪽) part creation + manifest
|
|
436
|
+
# registration — new module from the start (document_parts.py had
|
|
437
|
+
# modest headroom but this needed more than fit safely), per the WP-A
|
|
438
|
+
# rule above.
|
|
439
|
+
"src/hwpx/oxml/master_page_authoring.py",
|
|
440
|
+
# 6.13 (train 48): date field (hp:fieldBegin type=DATE) + proofreading
|
|
441
|
+
# mark field (type=PROOFREADING_MARKS_SIGN) authoring — new module
|
|
442
|
+
# from the start; paragraph.py hit exactly 1600 lines with just the
|
|
443
|
+
# two delegator methods (zero headroom left, resolved by the
|
|
444
|
+
# extraction below), per the WP-A rule above.
|
|
445
|
+
"src/hwpx/oxml/field_marks.py",
|
|
446
|
+
# 6.14 (train 48/debt3): footnote/endnote (각주/미주) authoring moved
|
|
447
|
+
# out of paragraph.py verbatim (no behavior change) to restore real
|
|
448
|
+
# headroom -- same escape valve as dutmal_compose.py/objects.py/
|
|
449
|
+
# field_marks.py above, per the WP-A rule.
|
|
450
|
+
"src/hwpx/oxml/note_authoring.py",
|
|
311
451
|
]
|
|
312
452
|
pythonVersion = "3.10"
|
|
313
453
|
typeCheckingMode = "basic"
|
|
@@ -69,6 +69,7 @@ from . import tracked as _tracked
|
|
|
69
69
|
|
|
70
70
|
if TYPE_CHECKING:
|
|
71
71
|
from ..form_fit.policy import FitPolicy
|
|
72
|
+
from ..objects.binary_item import BinaryItem
|
|
72
73
|
from ..oxml import (
|
|
73
74
|
HwpxOxmlDocument,
|
|
74
75
|
HwpxOxmlHeader,
|
|
@@ -862,6 +863,8 @@ class _LegacyFacade:
|
|
|
862
863
|
border_color: str = "#BFBFBF",
|
|
863
864
|
border_width: str = "0.12 mm",
|
|
864
865
|
fill_color: str | None = None,
|
|
866
|
+
fill_image: "str | BinaryItem | Mapping[str, object] | None" = None,
|
|
867
|
+
fill_gradient: Mapping[str, object] | None = None,
|
|
865
868
|
active_borders: Sequence[str] | None = None,
|
|
866
869
|
border_type: str = "SOLID",
|
|
867
870
|
) -> str:
|
|
@@ -869,13 +872,25 @@ class _LegacyFacade:
|
|
|
869
872
|
|
|
870
873
|
``border_type`` selects the OWPML line style (``SOLID``, ``DASH``,
|
|
871
874
|
``DOT``, ``DOUBLE_SLIM``, ``WAVE``, …); values outside the OWPML
|
|
872
|
-
vocabulary are rejected.
|
|
875
|
+
vocabulary are rejected. ``fill_color``/``fill_image``/``fill_gradient``
|
|
876
|
+
are mutually exclusive (OWPML ``hc:fillBrush`` choice).
|
|
873
877
|
"""
|
|
874
878
|
|
|
879
|
+
from .ns.styles import _resolve_fill_gradient, _resolve_fill_image
|
|
880
|
+
|
|
881
|
+
given = sum(1 for v in (fill_color, fill_image, fill_gradient) if v is not None)
|
|
882
|
+
if given > 1:
|
|
883
|
+
raise HwpxValueError(
|
|
884
|
+
"fill_color/fill_image/fill_gradient are mutually exclusive",
|
|
885
|
+
code="style-border-fill-conflict",
|
|
886
|
+
suggestion="Pass exactly one of fill_color, fill_image, fill_gradient.",
|
|
887
|
+
)
|
|
875
888
|
return self._root.ensure_border_fill(
|
|
876
889
|
border_color=border_color,
|
|
877
890
|
border_width=border_width,
|
|
878
891
|
fill_color=fill_color,
|
|
892
|
+
fill_image=_resolve_fill_image(fill_image),
|
|
893
|
+
fill_gradient=_resolve_fill_gradient(fill_gradient),
|
|
879
894
|
active_borders=active_borders,
|
|
880
895
|
border_type=border_type,
|
|
881
896
|
)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Highlight (``hp:markpenBegin``/``markpenEnd``) authoring and reading owner
|
|
3
|
+
behind the :class:`HwpxDocument` facade.
|
|
4
|
+
|
|
5
|
+
Real-corpus reversal (``hwpxlib_corpus/error__20251107__test*.hwpx``, the only
|
|
6
|
+
fixtures carrying this pair) plus the OWPML schema (``ParaList XML
|
|
7
|
+
schema.xml``) agree on the shape: both marks live inside a single ``hp:t``,
|
|
8
|
+
``markpenBegin`` carries an optional ``color``, ``markpenEnd`` carries no
|
|
9
|
+
attributes at all — pairing is positional (innermost open begin closes first),
|
|
10
|
+
not by id. :mod:`hwpx.tools.text_extractor` already reads this shape with a
|
|
11
|
+
per-``hp:t`` stack; :func:`list_highlights` exposes the same reading as a
|
|
12
|
+
public model instead of inline text markers.
|
|
13
|
+
|
|
14
|
+
Authoring is scoped to one run's text the same way ``doc.tracking.delete``
|
|
15
|
+
scopes tracked deletes: a match that only exists once inline markup pieces
|
|
16
|
+
are concatenated crosses a boundary this module refuses to split.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import re
|
|
22
|
+
from typing import TYPE_CHECKING
|
|
23
|
+
|
|
24
|
+
from ..errors import HwpxValueError
|
|
25
|
+
from ..objects.highlight import Highlight
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from hwpx.document import HwpxDocument
|
|
29
|
+
from ..oxml import HwpxOxmlParagraph
|
|
30
|
+
from ..oxml.body import TextSpan
|
|
31
|
+
|
|
32
|
+
#: OWPML ``hc:RGBColorType`` — ``#`` followed by exactly six hex digits.
|
|
33
|
+
_COLOR_RE = re.compile(r"#[0-9A-Fa-f]{6}")
|
|
34
|
+
|
|
35
|
+
#: Matches the real-corpus fixtures' brightest observed value; any
|
|
36
|
+
#: schema-valid hex is otherwise accepted.
|
|
37
|
+
DEFAULT_COLOR = "#FFFF00"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _validate_color(color: str) -> str:
|
|
41
|
+
if not isinstance(color, str) or not _COLOR_RE.fullmatch(color):
|
|
42
|
+
raise HwpxValueError(
|
|
43
|
+
f"highlight color must be a 6-digit hex value like '#FFFF00', got {color!r}",
|
|
44
|
+
code="text-highlight-color-invalid",
|
|
45
|
+
context={"color": color},
|
|
46
|
+
suggestion="Pass a colour matching #RRGGBB (hex digits, either case).",
|
|
47
|
+
)
|
|
48
|
+
return color
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _paragraph_has_highlightable_text(paragraph: "HwpxOxmlParagraph", match: str) -> bool:
|
|
52
|
+
"""Return whether *match* lives inside one contiguous inline text piece.
|
|
53
|
+
|
|
54
|
+
Mirrors ``hwpx._document.tracked._paragraph_has_replaceable_text``: a
|
|
55
|
+
match that is only present after concatenating text across inline
|
|
56
|
+
markup (an existing highlight, a tracked-change mark, …) is real but
|
|
57
|
+
cannot be wrapped safely, so that case raises here instead of falling
|
|
58
|
+
through to a generic "not found".
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
crosses_inline_markup = False
|
|
62
|
+
for run in paragraph.runs:
|
|
63
|
+
model = run.to_model()
|
|
64
|
+
for span in model.text_spans:
|
|
65
|
+
if match not in span.text:
|
|
66
|
+
continue
|
|
67
|
+
if match in span.leading_text or any(
|
|
68
|
+
match in markup.trailing_text for markup in span.marks
|
|
69
|
+
):
|
|
70
|
+
return True
|
|
71
|
+
crosses_inline_markup = True
|
|
72
|
+
|
|
73
|
+
if crosses_inline_markup:
|
|
74
|
+
raise HwpxValueError(
|
|
75
|
+
"match text crosses inline markup and cannot be wrapped safely",
|
|
76
|
+
code="text-highlight-match-crosses-markup",
|
|
77
|
+
context={"match": match},
|
|
78
|
+
suggestion="Target a substring that lives inside a single run.",
|
|
79
|
+
)
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def add_highlight(
|
|
84
|
+
doc: "HwpxDocument",
|
|
85
|
+
paragraph: "HwpxOxmlParagraph",
|
|
86
|
+
match: str,
|
|
87
|
+
*,
|
|
88
|
+
color: str = DEFAULT_COLOR,
|
|
89
|
+
) -> Highlight:
|
|
90
|
+
"""Wrap the first occurrence of *match* in *paragraph* in markpen marks."""
|
|
91
|
+
|
|
92
|
+
if not match:
|
|
93
|
+
raise HwpxValueError(
|
|
94
|
+
"match text must be a non-empty string",
|
|
95
|
+
code="text-highlight-match-empty",
|
|
96
|
+
suggestion="Pass the substring to highlight.",
|
|
97
|
+
)
|
|
98
|
+
validated_color = _validate_color(color)
|
|
99
|
+
|
|
100
|
+
if not _paragraph_has_highlightable_text(paragraph, match):
|
|
101
|
+
raise HwpxValueError(
|
|
102
|
+
"match text was not found in the paragraph",
|
|
103
|
+
code="text-highlight-match-not-found",
|
|
104
|
+
context={"match": match, "paragraphText": paragraph.text},
|
|
105
|
+
suggestion="Inspect paragraph.text for the actual string.",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
paragraph.add_highlight(color=validated_color, match=match)
|
|
109
|
+
return Highlight(text=match, color=validated_color, paragraph=paragraph)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _span_highlights(span: "TextSpan") -> list[tuple[str, "str | None"]]:
|
|
113
|
+
"""Yield (text, color) for every markpen pair closed within *span*.
|
|
114
|
+
|
|
115
|
+
A LIFO stack, same as ``text_extractor._render_text_element``'s
|
|
116
|
+
``highlight_stack`` — nested ``markpenBegin`` opens a new frame, the next
|
|
117
|
+
``markpenEnd`` closes the innermost one. A begin left open at the end of
|
|
118
|
+
the span (no matching end inside this ``hp:t``) is still reported, same
|
|
119
|
+
as that reader closing it defensively at ``hp:t`` end; an end with
|
|
120
|
+
nothing open is silently dropped rather than fabricated.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
results: list[tuple[str, "str | None"]] = []
|
|
124
|
+
stack: list[tuple["str | None", list[str]]] = []
|
|
125
|
+
|
|
126
|
+
for markup in span.marks:
|
|
127
|
+
element = markup.element
|
|
128
|
+
name = getattr(element, "name", None)
|
|
129
|
+
if name == "markpenBegin":
|
|
130
|
+
attributes = getattr(element, "attributes", None) or {}
|
|
131
|
+
stack.append((attributes.get("color"), []))
|
|
132
|
+
if markup.trailing_text:
|
|
133
|
+
stack[-1][1].append(markup.trailing_text)
|
|
134
|
+
continue
|
|
135
|
+
if name == "markpenEnd":
|
|
136
|
+
if stack:
|
|
137
|
+
mark_color, buffer = stack.pop()
|
|
138
|
+
results.append(("".join(buffer), mark_color))
|
|
139
|
+
if stack and markup.trailing_text:
|
|
140
|
+
stack[-1][1].append(markup.trailing_text)
|
|
141
|
+
continue
|
|
142
|
+
if stack and markup.trailing_text:
|
|
143
|
+
stack[-1][1].append(markup.trailing_text)
|
|
144
|
+
|
|
145
|
+
while stack:
|
|
146
|
+
mark_color, buffer = stack.pop()
|
|
147
|
+
results.append(("".join(buffer), mark_color))
|
|
148
|
+
return results
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def list_highlights(doc: "HwpxDocument") -> tuple[Highlight, ...]:
|
|
152
|
+
"""Return every markpen highlight in the document, in document order."""
|
|
153
|
+
|
|
154
|
+
results: list[Highlight] = []
|
|
155
|
+
for paragraph in doc.paragraphs:
|
|
156
|
+
for run in paragraph.runs:
|
|
157
|
+
model = run.to_model()
|
|
158
|
+
for span in model.text_spans:
|
|
159
|
+
for text, color in _span_highlights(span):
|
|
160
|
+
results.append(Highlight(text=text, color=color, paragraph=paragraph))
|
|
161
|
+
return tuple(results)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
__all__ = ["DEFAULT_COLOR", "add_highlight", "list_highlights"]
|
|
@@ -15,6 +15,7 @@ from ..objects.results import (
|
|
|
15
15
|
ParagraphFormatResult,
|
|
16
16
|
Units,
|
|
17
17
|
)
|
|
18
|
+
from ..oxml._document_primitives import NEW_NUM_KINDS
|
|
18
19
|
from ..oxml.namespaces import HH
|
|
19
20
|
from ._units import _mm_to_hwp_units, _pt_to_hwp_units
|
|
20
21
|
|
|
@@ -119,16 +120,31 @@ def set_paragraph_format(
|
|
|
119
120
|
keep_with_next: bool | None = None,
|
|
120
121
|
keep_lines: bool | None = None,
|
|
121
122
|
page_break_before: bool | None = None,
|
|
123
|
+
column_break: bool | None = None,
|
|
122
124
|
bottom_border: bool = False,
|
|
123
125
|
border_color: str = "#BFBFBF",
|
|
124
126
|
border_width: str = "0.12 mm",
|
|
127
|
+
tab_stops: Sequence[Mapping[str, Any]] | None = None,
|
|
128
|
+
auto_tab_left: bool | None = None,
|
|
129
|
+
auto_tab_right: bool | None = None,
|
|
125
130
|
) -> ParagraphFormatResult:
|
|
126
131
|
"""Apply paragraph-level formatting using human units.
|
|
127
132
|
|
|
128
133
|
Millimetre inputs are converted to HWP units; paragraph spacing uses
|
|
129
134
|
points; line spacing is stored as a percent value. ``keep_with_next`` /
|
|
130
135
|
``keep_lines`` / ``page_break_before`` set the paragraph's keep-together
|
|
131
|
-
(``<hh:breakSetting>``) flags via a freshly minted paraPr.
|
|
136
|
+
(``<hh:breakSetting>``) flags via a freshly minted paraPr. ``column_break``
|
|
137
|
+
is a different mechanism -- ``hp:p``'s own ``columnBreak`` attribute, a
|
|
138
|
+
per-paragraph-instance forced break (not a shared paraPr style property
|
|
139
|
+
like ``page_break_before``) -- applied directly to each target paragraph.
|
|
140
|
+
|
|
141
|
+
``tab_stops`` is a sequence of ``{"pos_mm": ..., "type": "LEFT"|"RIGHT"|
|
|
142
|
+
"CENTER"|"DECIMAL", "leader": "NONE"|...}`` mappings (``type``/``leader``
|
|
143
|
+
default to the real-corpus-majority ``"LEFT"``/``"NONE"``) — order is
|
|
144
|
+
meaningful, matching how real multi-stop documents list them
|
|
145
|
+
position-ascending. Passing ``tab_stops``/``auto_tab_left``/
|
|
146
|
+
``auto_tab_right`` mints (or reuses — dedupe) a ``hh:tabPr`` and wires
|
|
147
|
+
the paragraph's ``tabPrIDRef`` to it.
|
|
132
148
|
"""
|
|
133
149
|
|
|
134
150
|
if not doc._root.headers:
|
|
@@ -181,6 +197,10 @@ def set_paragraph_format(
|
|
|
181
197
|
if page_break_before is not None:
|
|
182
198
|
break_setting["page_break_before"] = bool(page_break_before)
|
|
183
199
|
|
|
200
|
+
wants_tab_definition = (
|
|
201
|
+
tab_stops is not None or auto_tab_left is not None or auto_tab_right is not None
|
|
202
|
+
)
|
|
203
|
+
|
|
184
204
|
if (
|
|
185
205
|
alignment is None
|
|
186
206
|
and line_spacing_percent is None
|
|
@@ -188,6 +208,8 @@ def set_paragraph_format(
|
|
|
188
208
|
and heading is None
|
|
189
209
|
and not bottom_border
|
|
190
210
|
and not break_setting
|
|
211
|
+
and not wants_tab_definition
|
|
212
|
+
and column_break is None
|
|
191
213
|
):
|
|
192
214
|
raise HwpxValueError(
|
|
193
215
|
"at least one paragraph formatting option is required",
|
|
@@ -195,6 +217,28 @@ def set_paragraph_format(
|
|
|
195
217
|
suggestion="Pass alignment, line_spacing_percent, or another option to change.",
|
|
196
218
|
)
|
|
197
219
|
|
|
220
|
+
tab_pr_id: str | None = None
|
|
221
|
+
if wants_tab_definition:
|
|
222
|
+
converted_stops: list[dict[str, object]] = []
|
|
223
|
+
for index, stop in enumerate(tab_stops or ()):
|
|
224
|
+
if "pos_mm" not in stop or stop["pos_mm"] is None:
|
|
225
|
+
raise HwpxValueError(
|
|
226
|
+
f"tab_stops[{index}] is missing 'pos_mm'",
|
|
227
|
+
code="paragraph-tab-pos-invalid",
|
|
228
|
+
context={"index": index},
|
|
229
|
+
suggestion="각 tab stop은 'pos_mm'(mm, 0 이상)가 필요합니다.",
|
|
230
|
+
)
|
|
231
|
+
converted_stops.append({
|
|
232
|
+
"pos": _mm_to_hwp_units(float(stop["pos_mm"])),
|
|
233
|
+
"type": stop.get("type"),
|
|
234
|
+
"leader": stop.get("leader"),
|
|
235
|
+
})
|
|
236
|
+
tab_pr_id = header.ensure_tab_definition(
|
|
237
|
+
tab_stops=converted_stops,
|
|
238
|
+
auto_tab_left=bool(auto_tab_left),
|
|
239
|
+
auto_tab_right=bool(auto_tab_right),
|
|
240
|
+
)
|
|
241
|
+
|
|
198
242
|
border: dict[str, str] | None = None
|
|
199
243
|
if bottom_border:
|
|
200
244
|
border_fill_id = header.ensure_border_fill(
|
|
@@ -212,22 +256,40 @@ def set_paragraph_format(
|
|
|
212
256
|
"ignoreMargin": "0",
|
|
213
257
|
}
|
|
214
258
|
|
|
259
|
+
# column_break bypasses paraPr entirely (it's hp:p's own attribute, not
|
|
260
|
+
# a shared style) -- only mint a new paraPr when one of the *other*
|
|
261
|
+
# options actually needs it, so a column_break-only call doesn't churn
|
|
262
|
+
# a needless duplicate paraPr id.
|
|
263
|
+
wants_para_pr_change = (
|
|
264
|
+
alignment is not None
|
|
265
|
+
or line_spacing_percent is not None
|
|
266
|
+
or bool(margins)
|
|
267
|
+
or heading is not None
|
|
268
|
+
or bottom_border
|
|
269
|
+
or bool(break_setting)
|
|
270
|
+
or wants_tab_definition
|
|
271
|
+
)
|
|
272
|
+
|
|
215
273
|
targets = _resolve_paragraph_targets(doc,
|
|
216
274
|
paragraph_index=paragraph_index,
|
|
217
275
|
paragraph_indexes=paragraph_indexes,
|
|
218
276
|
)
|
|
219
277
|
formatted: list[int] = []
|
|
220
278
|
for index, paragraph in targets:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
279
|
+
if wants_para_pr_change:
|
|
280
|
+
para_pr_id = header.ensure_paragraph_format(
|
|
281
|
+
base_para_pr_id=paragraph.para_pr_id_ref,
|
|
282
|
+
alignment=alignment,
|
|
283
|
+
line_spacing_percent=line_spacing_percent,
|
|
284
|
+
margins=margins,
|
|
285
|
+
heading=heading,
|
|
286
|
+
border=border,
|
|
287
|
+
break_setting=break_setting or None,
|
|
288
|
+
tab_pr_id_ref=tab_pr_id,
|
|
289
|
+
)
|
|
290
|
+
paragraph.para_pr_id_ref = para_pr_id
|
|
291
|
+
if column_break is not None:
|
|
292
|
+
paragraph.column_break = column_break
|
|
231
293
|
formatted.append(index)
|
|
232
294
|
|
|
233
295
|
return ParagraphFormatResult(
|
|
@@ -767,6 +829,61 @@ def set_page_number(
|
|
|
767
829
|
)
|
|
768
830
|
|
|
769
831
|
|
|
832
|
+
def restart_page_number(
|
|
833
|
+
doc: "HwpxDocument",
|
|
834
|
+
paragraph: "HwpxOxmlParagraph",
|
|
835
|
+
*,
|
|
836
|
+
number: int = 1,
|
|
837
|
+
kind: str = "PAGE",
|
|
838
|
+
) -> "HwpxOxmlInlineObject":
|
|
839
|
+
"""Restart *kind*'s running count at *number* from *paragraph* onward.
|
|
840
|
+
|
|
841
|
+
Inserts ``<hp:ctrl><hp:newNum num="{number}" numType="{kind}"/></hp:ctrl>``
|
|
842
|
+
— a section-mid restart point, distinct from ``set_page_number`` (which
|
|
843
|
+
places the *display* field in a header/footer). ``kind`` defaults to
|
|
844
|
+
``"PAGE"``, the only value real corpus (hwpxlib_corpus) observes; the
|
|
845
|
+
other six (``FOOTNOTE``/``ENDNOTE``/``PICTURE``/``TABLE``/``EQUATION``/
|
|
846
|
+
``TOTAL_PAGE``) are schema-legal but unattested.
|
|
847
|
+
"""
|
|
848
|
+
|
|
849
|
+
normalized_kind = str(kind or "PAGE").upper()
|
|
850
|
+
if normalized_kind not in NEW_NUM_KINDS:
|
|
851
|
+
raise HwpxValueError(
|
|
852
|
+
f"unsupported kind {kind!r}",
|
|
853
|
+
code="page-new-num-kind-invalid",
|
|
854
|
+
context={"kind": normalized_kind, "allowed": sorted(NEW_NUM_KINDS)},
|
|
855
|
+
suggestion="Use one of: " + ", ".join(sorted(NEW_NUM_KINDS)),
|
|
856
|
+
)
|
|
857
|
+
return paragraph.add_new_num(number=number, kind=normalized_kind)
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
def hide_page_elements(
|
|
861
|
+
doc: "HwpxDocument",
|
|
862
|
+
paragraph: "HwpxOxmlParagraph",
|
|
863
|
+
*,
|
|
864
|
+
header: bool = False,
|
|
865
|
+
footer: bool = False,
|
|
866
|
+
master_page: bool = False,
|
|
867
|
+
border: bool = False,
|
|
868
|
+
fill: bool = False,
|
|
869
|
+
page_num: bool = False,
|
|
870
|
+
) -> "HwpxOxmlInlineObject":
|
|
871
|
+
"""Hide the named page elements from *paragraph*'s page onward.
|
|
872
|
+
|
|
873
|
+
Inserts ``<hp:ctrl><hp:pageHiding .../></hp:ctrl>`` (``ParaList XML
|
|
874
|
+
schema.xml:148-163`` — six independent booleans, all default unhidden).
|
|
875
|
+
"""
|
|
876
|
+
|
|
877
|
+
return paragraph.add_page_hiding(
|
|
878
|
+
header=header,
|
|
879
|
+
footer=footer,
|
|
880
|
+
master_page=master_page,
|
|
881
|
+
border=border,
|
|
882
|
+
fill=fill,
|
|
883
|
+
page_num=page_num,
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
|
|
770
887
|
def remove_header(
|
|
771
888
|
doc: "HwpxDocument",
|
|
772
889
|
*,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
| 능력 영역 | 네임스페이스 |
|
|
11
11
|
|---|---|
|
|
12
|
-
| `shape-authoring`·`shape-escape-hatch`·`curve-objects`·`chart`·`equation` | `doc.shapes` |
|
|
12
|
+
| `shape-authoring`·`shape-escape-hatch`·`curve-objects`·`container-authoring`·`chart`·`equation` | `doc.shapes` |
|
|
13
13
|
| `picture`(BinData 절반) | `doc.media` |
|
|
14
14
|
| `redline` | `doc.tracking` |
|
|
15
15
|
| `memo`·`footnote-endnote` | `doc.notes` |
|