python-hwpx 3.8.0__tar.gz → 4.0.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-4.0.0/PKG-INFO +181 -0
- python_hwpx-4.0.0/README.md +132 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/pyproject.toml +3 -1
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/__init__.py +98 -43
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/persistence.py +27 -31
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/document.py +0 -25
- python_hwpx-4.0.0/src/hwpx/errors.py +70 -0
- python_hwpx-4.0.0/src/hwpx/experimental.py +48 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/mutation_report.py +22 -4
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/table_patch.py +19 -4
- python_hwpx-4.0.0/src/python_hwpx.egg-info/PKG-INFO +181 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/python_hwpx.egg-info/SOURCES.txt +5 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_save_api.py +0 -18
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_compose.py +1 -1
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_existing_document_format_editing.py +2 -2
- python_hwpx-4.0.0/tests/test_mutation_contract_unification.py +104 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_oxml_modularization.py +15 -1
- python_hwpx-4.0.0/tests/test_schema_freeze.py +219 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_split_merged_cell.py +1 -1
- python_hwpx-4.0.0/tests/test_stable_surface.py +145 -0
- python_hwpx-3.8.0/PKG-INFO +0 -344
- python_hwpx-3.8.0/README.md +0 -295
- python_hwpx-3.8.0/src/python_hwpx.egg-info/PKG-INFO +0 -344
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/LICENSE +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/NOTICE +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/setup.cfg +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/_units.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/fields.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/layout.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/media.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/memos.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/shapes.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/_document/tracked.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/_batch_verification.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/bundle.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/catalog.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/dump.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/mapping.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/model.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/native.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/blueprint/replay.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/catalog.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/cli.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/commands.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/document.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/form_plan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/model.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/path.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/query.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/agent/story.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/authoring.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/benchmark/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/benchmark/blind_eval.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/body_patch.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/builder/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/builder/core.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/builder/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/badges.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/corpus/corpus.json +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/corpus/meeting_summary.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/corpus/notice.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/corpus/report_table.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/corpus.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/roundtrip_batch.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/conformance/runner.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/data/Skeleton.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/_support.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/composer.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/harvest.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/plan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/fragments/body.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/fragments/heading.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/fragments/info_table.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/fragments/title.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/profile.json +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/application_form/template.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/home_notice/fragments/body.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/home_notice/fragments/heading.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/home_notice/fragments/title.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/home_notice/profile.json +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/home_notice/template.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/fragments/body.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/fragments/heading.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/fragments/info_table.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/fragments/title.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/profile.json +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/official_notice/template.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/fragments/body.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/fragments/heading.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/fragments/info_table.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/fragments/title.xml +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/profile.json +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/profiles/report/template.hwpx +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/design/validator.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/equation/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/equation/eqedit.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/equation/mathml.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/equation/render.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/equation/tokens.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/evalplan_fill.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/compose.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/ir.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/measure.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/parser.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/exam/profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/fill_residue.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fill.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/apply.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/engine.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/measure.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/policy.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/seal.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/form_fit/wordbox.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/formfill_quality.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/guidance_scan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/ingest/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/ingest/base.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/ingest/hwpx_converter.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/layout/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/layout/lint.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/layout/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/opc/package.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/opc/relationships.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/opc/security.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/opc/xml_utils.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/_document_impl.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/_document_primitives.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/body.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/canonical_defaults.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/common.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/document.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/document_parts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/header.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/header_part.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/memo.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/namespaces.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/numbering.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/objects.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/paragraph.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/parser.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/run.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/schema.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/section.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/section_format.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/section_story.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/simple_parts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/table.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/oxml/utils.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/package.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/patch.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/presets/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/presets/proposal.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/py.typed +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/quality/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/quality/ledger.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/quality/policy.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/quality/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/quality/save_pipeline.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/template_formfit.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/templates.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/_schemas/header.xsd +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/_schemas/section.xsd +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/advanced_generators.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/archive_cli.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/doc_diff.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/document_viewer.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/exporter.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/__main__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/catalog.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/generator.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/minimize.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/fuzz/runner.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/generic_inventory.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/id_integrity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/idempotence.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/ir_equality.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/layout_preview.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/mail_merge.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/markdown_export.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/object_finder.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/official_lint.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/package_reconcile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/package_validator.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/page_guard.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/pii.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/read_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/recover.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/redline.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/repair.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/report_parser.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/report_utils.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/roundtrip_diff.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/style_profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/table_cleanup.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/table_compute.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/table_navigation.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/template_analyzer.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/text_extract_cli.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/text_extractor.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/toc_author.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/toc_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/tools/validator.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/__init__.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/_hancom_open_rate.ps1 +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/_refresh_hwpx_mac.applescript +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/_render_hwpx.ps1 +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/_render_hwpx_mac.applescript +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/detectors.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/diff.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/fixture_corpus.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/hancom_worker.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/masks.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/oracle.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/page_qa.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/qa_contracts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/qa_metrics.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/hwpx/visual/report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/python_hwpx.egg-info/entry_points.txt +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/python_hwpx.egg-info/requires.txt +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/src/python_hwpx.egg-info/top_level.txt +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_advanced_generators.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_blueprint_contracts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_blueprint_dump.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_blueprint_replay.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_catalog.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_cli.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_commands.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_contracts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_document.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_mixed_form.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_path_query.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_agent_story_commands.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_native_toc.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_profile_routing.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_profile_routing_oracle.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_quality_corpus.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_render_check.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_authoring_v2_block_validation.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_blind_eval_fixture.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_body_patch.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_builder_core.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_builder_plan_v2.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_builder_vertical_slice.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_byte_patch_identity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_cell_line_spacing.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_comment_node_robustness.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_conformance.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_corpus_read_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_corpus_toc_verify.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_coverage_promotion.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_coverage_targets.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_design_builder.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_deviations_registry.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_doc_diff.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_context_manager.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_facade_surface.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_formatting.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_plan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_plan_computed_fields.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_document_viewer.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_equation_converter.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_equation_render.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_evalplan_fill.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_compose_oracle.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_fixtures.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_ir.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_measure.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_parser.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_exam_profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_fill_residue.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fields.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fill_split_run.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fit.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fit_integration.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fit_seal.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fit_seal_placement.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_form_fit_wordbox.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_formfill_differential_driver.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_formfill_quality.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_fuzz_catalog_derive_expected.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_fuzz_loop.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_fuzz_regressions.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_gap_closure_tools.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_government_report_preset.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_government_table_profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_guidance_scan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_hancom_render_worker.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_hp_tab_support.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_hwpxlib_corpus_read.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_id_generator_range.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_id_integrity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_image_object_workflow.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_ingest.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_inline_models.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_integration_hwpx_compatibility.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_integration_roundtrip.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_kordoc_absorption.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_layout_cache_scope.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_layout_lint.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_layout_preview.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_m9_p0_spike_tools.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mail_merge_fit.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mail_merge_table_compute.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mail_merge_xlsx.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_markdown_export.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_memo_and_style_editing.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mixed_form_plan.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mutation_report.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_mutation_report_projections.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_namespace_handling.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_new_features.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_official_document_style.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_official_lint_gongmun_gate.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_official_lint_tableaware.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_opc_package.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_open_safety_corpus.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_openrate.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_oxml_parsing.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_packaging_license_metadata.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_packaging_py_typed.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_paragraph_keep_together.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_paragraph_section_management.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_pii.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_pii_leak_sweep.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_pii_structural.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_pii_wiring.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_proposal_preset.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_public_runtime_boundary.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_question_split_detector.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_read_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_recover_broken_zip.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_redline_authoring.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_redline_verify.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_repair_repack.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_report_parser.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_report_utils.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_repr_snapshots.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_rhwp_t1_gates.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_rhwp_t2_verification.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_roundtrip_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_row_heights.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_save_pipeline.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_save_pipeline_no_bypass.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_section_headers.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_set_paragraph_format_keep.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_skeleton_template_ids.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_split_cell.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_style_profile.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_table_cleanup.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_table_navigation.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_table_patch.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_table_patch_dryrun.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_table_patch_m105.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_tables_default_border.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_template_analyzer_enrichment.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_template_formfit.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_text_extractor_annotations.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_toc_author.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_toc_fidelity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_validation_severity.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_validator_comment_nodes.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_version_metadata.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_visual_fixture_corpus.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_visual_oracle.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_visual_oracle_budget.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_visual_qa_contracts.py +0 -0
- {python_hwpx-3.8.0 → python_hwpx-4.0.0}/tests/test_visual_qa_metrics.py +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-hwpx
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
|
|
5
|
+
Author: python-hwpx Maintainers
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/airmang/python-hwpx
|
|
8
|
+
Project-URL: Documentation, https://airmang.github.io/python-hwpx/
|
|
9
|
+
Project-URL: Issues, https://github.com/airmang/python-hwpx/issues
|
|
10
|
+
Keywords: hwp,hwpx,hancom,opc,xml,document-automation,validation,template
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
License-File: NOTICE
|
|
23
|
+
Requires-Dist: lxml<7,>=4.9
|
|
24
|
+
Provides-Extra: visual
|
|
25
|
+
Requires-Dist: pymupdf>=1.24; extra == "visual"
|
|
26
|
+
Requires-Dist: pillow>=10.0; extra == "visual"
|
|
27
|
+
Requires-Dist: numpy>=1.26; extra == "visual"
|
|
28
|
+
Provides-Extra: xlsx
|
|
29
|
+
Requires-Dist: openpyxl>=3.1; extra == "xlsx"
|
|
30
|
+
Provides-Extra: preview
|
|
31
|
+
Requires-Dist: latex2mathml>=3.77; extra == "preview"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
36
|
+
Requires-Dist: latex2mathml>=3.77; extra == "dev"
|
|
37
|
+
Provides-Extra: test
|
|
38
|
+
Requires-Dist: build>=1.0; extra == "test"
|
|
39
|
+
Requires-Dist: numpy>=1.26; extra == "test"
|
|
40
|
+
Requires-Dist: pillow>=10.0; extra == "test"
|
|
41
|
+
Requires-Dist: pytest>=7.4; extra == "test"
|
|
42
|
+
Requires-Dist: pytest-cov>=5.0; extra == "test"
|
|
43
|
+
Requires-Dist: ruff>=0.12; extra == "test"
|
|
44
|
+
Requires-Dist: latex2mathml>=3.77; extra == "test"
|
|
45
|
+
Provides-Extra: typecheck
|
|
46
|
+
Requires-Dist: mypy>=1.10; extra == "typecheck"
|
|
47
|
+
Requires-Dist: pyright>=1.1.390; extra == "typecheck"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<h1 align="center">python-hwpx</h1>
|
|
52
|
+
<p align="center">
|
|
53
|
+
<strong>한컴 없이 HWPX를 읽고, 고치고, 만드는 순수 파이썬 라이브러리</strong>
|
|
54
|
+
</p>
|
|
55
|
+
<p align="center">
|
|
56
|
+
<a href="https://pypi.org/project/python-hwpx/"><img src="https://img.shields.io/pypi/v/python-hwpx?color=blue&label=PyPI" alt="PyPI"></a>
|
|
57
|
+
<a href="https://pypi.org/project/python-hwpx/"><img src="https://img.shields.io/pypi/pyversions/python-hwpx" alt="Python"></a>
|
|
58
|
+
<a href="https://github.com/airmang/python-hwpx/actions/workflows/tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/airmang/python-hwpx/tests.yml?branch=main&label=tests" alt="Tests"></a>
|
|
59
|
+
<a href="https://airmang.github.io/python-hwpx/corpus-metrics.html"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fairmang.github.io%2Fpython-hwpx%2F_static%2Fbadge-hancom-open.json" alt="Hancom open"></a>
|
|
60
|
+
<a href="https://github.com/airmang/python-hwpx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License"></a>
|
|
61
|
+
</p>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
<p align="center">한국어 | <a href="README_EN.md">English</a></p>
|
|
65
|
+
|
|
66
|
+
기존 문서는 손댄 곳만 고치고(미수정 영역은 바이트 그대로), 새 문서는 실제
|
|
67
|
+
한컴오피스가 받아들이는 형태로 만듭니다. HWPX는 ZIP+XML(OWPML/OPC) 구조라
|
|
68
|
+
Windows·macOS·Linux·CI 어디서든 순수 파이썬으로 동작합니다.
|
|
69
|
+
|
|
70
|
+
| | 레포 | 역할 |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| 📦 | **`python-hwpx`** | 순수 파이썬 HWPX 코어 (이 레포) |
|
|
73
|
+
| 🔌 | [`hwpx-mcp-server`](https://github.com/airmang/hwpx-mcp-server) | MCP 클라이언트(Claude Desktop 등)에서 HWPX 조작 |
|
|
74
|
+
| 🎯 | [`hwpx-plugin`](https://github.com/airmang/hwpx-plugins) | 에이전트용 플러그인·스킬 번들 |
|
|
75
|
+
|
|
76
|
+
## 시작하기
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install python-hwpx # Python 3.10+
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from hwpx import HwpxDocument
|
|
84
|
+
|
|
85
|
+
doc = HwpxDocument.open("보고서.hwpx")
|
|
86
|
+
doc.add_paragraph("자동화로 추가한 문단입니다.")
|
|
87
|
+
doc.save_to_path("보고서-수정.hwpx")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 무엇을 하나
|
|
91
|
+
|
|
92
|
+
- **읽기·추출** — 텍스트/HTML/rich Markdown 내보내기(서식·중첩 표·각주 보존), XPath 객체 탐색
|
|
93
|
+
- **편집** — 문단·표·이미지·머리글/바닥글·메모·각주, 줄간격·여백·쪽번호 등 서식
|
|
94
|
+
- **양식 채우기** — 라벨·경로 기반 셀 채움, 바이트 보존 구조 편집(행·열·오토핏·shrink-to-fit)
|
|
95
|
+
- **생성** — 조립형 builder, 공문 lint·결재란, 사진대지·명패·조직도, mail merge, 신구대조표
|
|
96
|
+
- **변경추적·목차** — redline 저작, 네이티브 목차·상호참조
|
|
97
|
+
- **검증·안전** — XSD·패키지 검증 CLI, 열림 안전 게이트, 모든 쓰기에 영수증(`MutationReport`)
|
|
98
|
+
|
|
99
|
+
자세한 내용: [사용 가이드](docs/usage.md) · [API 레퍼런스](https://airmang.github.io/python-hwpx/) · [안정 API 표면](docs/stable-api.md) · [예제](docs/examples.md)
|
|
100
|
+
|
|
101
|
+
### 양식 채우기 — 서식은 그대로, 값만
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
doc = HwpxDocument.open("신청서.hwpx")
|
|
105
|
+
result = doc.fill_by_path({
|
|
106
|
+
"성명 > right": "홍길동",
|
|
107
|
+
"소속 > right": "플랫폼팀",
|
|
108
|
+
})
|
|
109
|
+
doc.save_to_path("신청서-작성완료.hwpx")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
라벨 기준으로 셀을 찾아 채우고, 손대지 않은 영역은 원본 바이트가 그대로 유지됩니다.
|
|
113
|
+
|
|
114
|
+
### 저장에는 영수증이 따라옵니다
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
report = doc.save_to_path("결과.hwpx", return_report=True)
|
|
118
|
+
print(report.actual_mode) # "patch" — 문서 재조립 없이 저장됨
|
|
119
|
+
print(report.preservation.untouched_part_payloads.to_dict())
|
|
120
|
+
# {"verified": 17, "changed": 0}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
요청한 보존 등급을 지킬 수 없으면 아무것도 쓰지 않고 실패합니다(fail-closed).
|
|
124
|
+
전체 규칙은 [안전한 쓰기 계약](docs/safe-write-contract.md)에 있습니다.
|
|
125
|
+
|
|
126
|
+
## 실측으로 말합니다
|
|
127
|
+
|
|
128
|
+
산출물 전수를 실제 한컴오피스로 측정해 그대로 공개합니다(동결 코퍼스 N=497):
|
|
129
|
+
|
|
130
|
+
- **한컴 오픈 476/476 all-pass** — 우리가 만든 파일을 실한컴이 전부 엽니다
|
|
131
|
+
- **미수정 영역 바이트 보존 497/497** · 개인정보 0-leak
|
|
132
|
+
- **렌더 검증 416/476** + 정직 버킷 43 — 한컴 자체가 PDF export를 거부한 케이스도 숨기지 않고 집계
|
|
133
|
+
- 낮은 숫자도 그대로 발행합니다 — 전체 수치·주의사항: [실측 코퍼스 메트릭](https://airmang.github.io/python-hwpx/corpus-metrics.html)
|
|
134
|
+
|
|
135
|
+
기능별로 되는 것과 안 되는 것은 [지원 매트릭스](docs/support-matrix.md)에 등급으로
|
|
136
|
+
명시되어 있습니다. 현재 개발 상태는 Alpha입니다 — API는 바뀔 수 있습니다.
|
|
137
|
+
|
|
138
|
+
> 위 수치는 *생성물 수용률* 축입니다(만든 파일을 실한컴이 받는가). 문서 *파싱 recall*과는
|
|
139
|
+
> 다른 축이므로 파서 프로젝트 수치와 병치 비교하지 마세요.
|
|
140
|
+
|
|
141
|
+
## 비교
|
|
142
|
+
|
|
143
|
+
| | python-hwpx | pyhwpx | pyhwp |
|
|
144
|
+
|---|---|---|---|
|
|
145
|
+
| **대상 포맷** | `.hwpx` (OWPML/OPC) | `.hwpx` | `.hwp` (v5 바이너리) |
|
|
146
|
+
| **한/글 설치** | 불필요 | 필요 (Windows COM) | 불필요 |
|
|
147
|
+
| **크로스 플랫폼** | ✅ Linux / macOS / Windows / CI | ❌ Windows 전용 | ✅ |
|
|
148
|
+
| **편집/생성 API** | ✅ | ✅ (COM) | ❌ 대부분 읽기 |
|
|
149
|
+
| **AI 에이전트 연동 (MCP)** | ✅ | ❌ | ❌ |
|
|
150
|
+
|
|
151
|
+
> HWP(v5 바이너리)는 지원하지 않습니다. 한컴오피스에서 HWPX로 변환 후 사용하세요.
|
|
152
|
+
|
|
153
|
+
## 알려진 제약
|
|
154
|
+
|
|
155
|
+
- `add_shape()` / `add_control()`은 한/글이 요구하는 모든 하위 요소를 생성하지 않습니다.
|
|
156
|
+
- `<hp:pic>` 그림 개체의 완전 자동 생성은 제공하지 않습니다.
|
|
157
|
+
- 암호화된 HWPX는 지원하지 않습니다.
|
|
158
|
+
|
|
159
|
+
## 기여하기
|
|
160
|
+
|
|
161
|
+
[help wanted](https://github.com/airmang/python-hwpx/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) ·
|
|
162
|
+
[로드맵](https://github.com/airmang/python-hwpx/milestones) ·
|
|
163
|
+
[Discussions](https://github.com/airmang/python-hwpx/discussions) ·
|
|
164
|
+
[내부 실전 가이드](docs/internals/) ·
|
|
165
|
+
[CONTRIBUTING](CONTRIBUTING.md)
|
|
166
|
+
|
|
167
|
+
HWPX 내부 구조가 처음이라면 [내부 실전 가이드](docs/internals/)부터 — 실제 한/글
|
|
168
|
+
동작에서 확인된 조판 캐시·목차 필드·OPC 재패킹 같은 실전 지식을 정리해 두었습니다.
|
|
169
|
+
|
|
170
|
+
## 감사의 말
|
|
171
|
+
|
|
172
|
+
아래 공개 표준·프로젝트에 빚지고 있습니다.
|
|
173
|
+
|
|
174
|
+
- **[OWPML — 개방형 워드프로세서 마크업 언어 (KS X 6101)](https://www.kssn.net/search/stddetail.do?itemNo=K001010119985)** — HWPX가 기반하는 한국 산업 표준
|
|
175
|
+
- **[hancom-io/hwpx-owpml-model](https://github.com/hancom-io/hwpx-owpml-model)** — OWPML 요소 구조 참조 모델 · **[neolord0/hwpxlib](https://github.com/neolord0/hwpxlib)** — 오라클 샘플 코퍼스
|
|
176
|
+
- **[edwardkim/rhwp](https://github.com/edwardkim/rhwp)** — 멱등성·검증 게이트 설계 영감
|
|
177
|
+
- **범정부오피스** — 공무 문서 편집 워크플로 아이디어
|
|
178
|
+
|
|
179
|
+
## License · Maintainer
|
|
180
|
+
|
|
181
|
+
Apache-2.0 ([LICENSE](LICENSE) · [NOTICE](NOTICE)) — **Kohkyuhyun** [@airmang](https://github.com/airmang) · [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">python-hwpx</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>한컴 없이 HWPX를 읽고, 고치고, 만드는 순수 파이썬 라이브러리</strong>
|
|
5
|
+
</p>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://pypi.org/project/python-hwpx/"><img src="https://img.shields.io/pypi/v/python-hwpx?color=blue&label=PyPI" alt="PyPI"></a>
|
|
8
|
+
<a href="https://pypi.org/project/python-hwpx/"><img src="https://img.shields.io/pypi/pyversions/python-hwpx" alt="Python"></a>
|
|
9
|
+
<a href="https://github.com/airmang/python-hwpx/actions/workflows/tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/airmang/python-hwpx/tests.yml?branch=main&label=tests" alt="Tests"></a>
|
|
10
|
+
<a href="https://airmang.github.io/python-hwpx/corpus-metrics.html"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fairmang.github.io%2Fpython-hwpx%2F_static%2Fbadge-hancom-open.json" alt="Hancom open"></a>
|
|
11
|
+
<a href="https://github.com/airmang/python-hwpx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License"></a>
|
|
12
|
+
</p>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">한국어 | <a href="README_EN.md">English</a></p>
|
|
16
|
+
|
|
17
|
+
기존 문서는 손댄 곳만 고치고(미수정 영역은 바이트 그대로), 새 문서는 실제
|
|
18
|
+
한컴오피스가 받아들이는 형태로 만듭니다. HWPX는 ZIP+XML(OWPML/OPC) 구조라
|
|
19
|
+
Windows·macOS·Linux·CI 어디서든 순수 파이썬으로 동작합니다.
|
|
20
|
+
|
|
21
|
+
| | 레포 | 역할 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| 📦 | **`python-hwpx`** | 순수 파이썬 HWPX 코어 (이 레포) |
|
|
24
|
+
| 🔌 | [`hwpx-mcp-server`](https://github.com/airmang/hwpx-mcp-server) | MCP 클라이언트(Claude Desktop 등)에서 HWPX 조작 |
|
|
25
|
+
| 🎯 | [`hwpx-plugin`](https://github.com/airmang/hwpx-plugins) | 에이전트용 플러그인·스킬 번들 |
|
|
26
|
+
|
|
27
|
+
## 시작하기
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install python-hwpx # Python 3.10+
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from hwpx import HwpxDocument
|
|
35
|
+
|
|
36
|
+
doc = HwpxDocument.open("보고서.hwpx")
|
|
37
|
+
doc.add_paragraph("자동화로 추가한 문단입니다.")
|
|
38
|
+
doc.save_to_path("보고서-수정.hwpx")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 무엇을 하나
|
|
42
|
+
|
|
43
|
+
- **읽기·추출** — 텍스트/HTML/rich Markdown 내보내기(서식·중첩 표·각주 보존), XPath 객체 탐색
|
|
44
|
+
- **편집** — 문단·표·이미지·머리글/바닥글·메모·각주, 줄간격·여백·쪽번호 등 서식
|
|
45
|
+
- **양식 채우기** — 라벨·경로 기반 셀 채움, 바이트 보존 구조 편집(행·열·오토핏·shrink-to-fit)
|
|
46
|
+
- **생성** — 조립형 builder, 공문 lint·결재란, 사진대지·명패·조직도, mail merge, 신구대조표
|
|
47
|
+
- **변경추적·목차** — redline 저작, 네이티브 목차·상호참조
|
|
48
|
+
- **검증·안전** — XSD·패키지 검증 CLI, 열림 안전 게이트, 모든 쓰기에 영수증(`MutationReport`)
|
|
49
|
+
|
|
50
|
+
자세한 내용: [사용 가이드](docs/usage.md) · [API 레퍼런스](https://airmang.github.io/python-hwpx/) · [안정 API 표면](docs/stable-api.md) · [예제](docs/examples.md)
|
|
51
|
+
|
|
52
|
+
### 양식 채우기 — 서식은 그대로, 값만
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
doc = HwpxDocument.open("신청서.hwpx")
|
|
56
|
+
result = doc.fill_by_path({
|
|
57
|
+
"성명 > right": "홍길동",
|
|
58
|
+
"소속 > right": "플랫폼팀",
|
|
59
|
+
})
|
|
60
|
+
doc.save_to_path("신청서-작성완료.hwpx")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
라벨 기준으로 셀을 찾아 채우고, 손대지 않은 영역은 원본 바이트가 그대로 유지됩니다.
|
|
64
|
+
|
|
65
|
+
### 저장에는 영수증이 따라옵니다
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
report = doc.save_to_path("결과.hwpx", return_report=True)
|
|
69
|
+
print(report.actual_mode) # "patch" — 문서 재조립 없이 저장됨
|
|
70
|
+
print(report.preservation.untouched_part_payloads.to_dict())
|
|
71
|
+
# {"verified": 17, "changed": 0}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
요청한 보존 등급을 지킬 수 없으면 아무것도 쓰지 않고 실패합니다(fail-closed).
|
|
75
|
+
전체 규칙은 [안전한 쓰기 계약](docs/safe-write-contract.md)에 있습니다.
|
|
76
|
+
|
|
77
|
+
## 실측으로 말합니다
|
|
78
|
+
|
|
79
|
+
산출물 전수를 실제 한컴오피스로 측정해 그대로 공개합니다(동결 코퍼스 N=497):
|
|
80
|
+
|
|
81
|
+
- **한컴 오픈 476/476 all-pass** — 우리가 만든 파일을 실한컴이 전부 엽니다
|
|
82
|
+
- **미수정 영역 바이트 보존 497/497** · 개인정보 0-leak
|
|
83
|
+
- **렌더 검증 416/476** + 정직 버킷 43 — 한컴 자체가 PDF export를 거부한 케이스도 숨기지 않고 집계
|
|
84
|
+
- 낮은 숫자도 그대로 발행합니다 — 전체 수치·주의사항: [실측 코퍼스 메트릭](https://airmang.github.io/python-hwpx/corpus-metrics.html)
|
|
85
|
+
|
|
86
|
+
기능별로 되는 것과 안 되는 것은 [지원 매트릭스](docs/support-matrix.md)에 등급으로
|
|
87
|
+
명시되어 있습니다. 현재 개발 상태는 Alpha입니다 — API는 바뀔 수 있습니다.
|
|
88
|
+
|
|
89
|
+
> 위 수치는 *생성물 수용률* 축입니다(만든 파일을 실한컴이 받는가). 문서 *파싱 recall*과는
|
|
90
|
+
> 다른 축이므로 파서 프로젝트 수치와 병치 비교하지 마세요.
|
|
91
|
+
|
|
92
|
+
## 비교
|
|
93
|
+
|
|
94
|
+
| | python-hwpx | pyhwpx | pyhwp |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| **대상 포맷** | `.hwpx` (OWPML/OPC) | `.hwpx` | `.hwp` (v5 바이너리) |
|
|
97
|
+
| **한/글 설치** | 불필요 | 필요 (Windows COM) | 불필요 |
|
|
98
|
+
| **크로스 플랫폼** | ✅ Linux / macOS / Windows / CI | ❌ Windows 전용 | ✅ |
|
|
99
|
+
| **편집/생성 API** | ✅ | ✅ (COM) | ❌ 대부분 읽기 |
|
|
100
|
+
| **AI 에이전트 연동 (MCP)** | ✅ | ❌ | ❌ |
|
|
101
|
+
|
|
102
|
+
> HWP(v5 바이너리)는 지원하지 않습니다. 한컴오피스에서 HWPX로 변환 후 사용하세요.
|
|
103
|
+
|
|
104
|
+
## 알려진 제약
|
|
105
|
+
|
|
106
|
+
- `add_shape()` / `add_control()`은 한/글이 요구하는 모든 하위 요소를 생성하지 않습니다.
|
|
107
|
+
- `<hp:pic>` 그림 개체의 완전 자동 생성은 제공하지 않습니다.
|
|
108
|
+
- 암호화된 HWPX는 지원하지 않습니다.
|
|
109
|
+
|
|
110
|
+
## 기여하기
|
|
111
|
+
|
|
112
|
+
[help wanted](https://github.com/airmang/python-hwpx/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) ·
|
|
113
|
+
[로드맵](https://github.com/airmang/python-hwpx/milestones) ·
|
|
114
|
+
[Discussions](https://github.com/airmang/python-hwpx/discussions) ·
|
|
115
|
+
[내부 실전 가이드](docs/internals/) ·
|
|
116
|
+
[CONTRIBUTING](CONTRIBUTING.md)
|
|
117
|
+
|
|
118
|
+
HWPX 내부 구조가 처음이라면 [내부 실전 가이드](docs/internals/)부터 — 실제 한/글
|
|
119
|
+
동작에서 확인된 조판 캐시·목차 필드·OPC 재패킹 같은 실전 지식을 정리해 두었습니다.
|
|
120
|
+
|
|
121
|
+
## 감사의 말
|
|
122
|
+
|
|
123
|
+
아래 공개 표준·프로젝트에 빚지고 있습니다.
|
|
124
|
+
|
|
125
|
+
- **[OWPML — 개방형 워드프로세서 마크업 언어 (KS X 6101)](https://www.kssn.net/search/stddetail.do?itemNo=K001010119985)** — HWPX가 기반하는 한국 산업 표준
|
|
126
|
+
- **[hancom-io/hwpx-owpml-model](https://github.com/hancom-io/hwpx-owpml-model)** — OWPML 요소 구조 참조 모델 · **[neolord0/hwpxlib](https://github.com/neolord0/hwpxlib)** — 오라클 샘플 코퍼스
|
|
127
|
+
- **[edwardkim/rhwp](https://github.com/edwardkim/rhwp)** — 멱등성·검증 게이트 설계 영감
|
|
128
|
+
- **범정부오피스** — 공무 문서 편집 워크플로 아이디어
|
|
129
|
+
|
|
130
|
+
## License · Maintainer
|
|
131
|
+
|
|
132
|
+
Apache-2.0 ([LICENSE](LICENSE) · [NOTICE](NOTICE)) — **Kohkyuhyun** [@airmang](https://github.com/airmang) · [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-hwpx"
|
|
7
|
-
version = "
|
|
7
|
+
version = "4.0.0"
|
|
8
8
|
description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -116,6 +116,7 @@ python_version = "3.10"
|
|
|
116
116
|
follow_imports = "skip"
|
|
117
117
|
files = [
|
|
118
118
|
"src/hwpx/document.py",
|
|
119
|
+
"src/hwpx/errors.py",
|
|
119
120
|
"src/hwpx/mutation_report.py",
|
|
120
121
|
"src/hwpx/equation/__init__.py",
|
|
121
122
|
"src/hwpx/equation/tokens.py",
|
|
@@ -170,6 +171,7 @@ ignore_missing_imports = true
|
|
|
170
171
|
# both central facades and every extracted/touched runtime owner to the gate.
|
|
171
172
|
include = [
|
|
172
173
|
"src/hwpx/document.py",
|
|
174
|
+
"src/hwpx/errors.py",
|
|
173
175
|
"src/hwpx/mutation_report.py",
|
|
174
176
|
"src/hwpx/equation/__init__.py",
|
|
175
177
|
"src/hwpx/equation/tokens.py",
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""High-level utilities for working with HWPX documents.
|
|
2
|
+
"""High-level utilities for working with HWPX documents.
|
|
3
3
|
|
|
4
|
+
최상위 ``from hwpx import ...`` 표면은 세 계층으로 나뉩니다(정책·전수 목록:
|
|
5
|
+
``docs/stable-api.md``):
|
|
6
|
+
|
|
7
|
+
- **stable** — ``__all__``에 있는 이름. 계약이 굳었고 major 경계에서만 깨질 수 있음.
|
|
8
|
+
- **experimental** — 계약이 유동적. ``from hwpx.experimental import ...``로 쓰세요.
|
|
9
|
+
최상위 재내보내기는 하위 호환을 위해 유지하되 접근 시 ``DeprecationWarning``이 나며
|
|
10
|
+
다음 major에서 제거될 예정입니다.
|
|
11
|
+
- **deprecated** — 대체 경로로 이전하세요. 접근 시 ``DeprecationWarning``이 납니다.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import importlib
|
|
15
|
+
import warnings
|
|
4
16
|
from importlib.metadata import PackageNotFoundError, version as _metadata_version
|
|
5
17
|
|
|
6
18
|
|
|
@@ -11,13 +23,94 @@ def _resolve_version() -> str:
|
|
|
11
23
|
except PackageNotFoundError:
|
|
12
24
|
return "0+unknown"
|
|
13
25
|
|
|
26
|
+
|
|
27
|
+
# --- experimental / deprecated 최상위 표면 (지연 접근, 접근 시 경고) ---------------
|
|
28
|
+
#
|
|
29
|
+
# stable 이름은 아래에서 eager import 되어 모듈 전역에 존재하므로 ``__getattr__``이
|
|
30
|
+
# 호출되지 않습니다(=경고 없음). 여기 등록된 이름만 지연 해석되어 경고를 냅니다.
|
|
31
|
+
# 4.0.0에서 제거되는 이름은 0개 — 모두 계속 import 가능합니다.
|
|
32
|
+
|
|
33
|
+
_EXPERIMENTAL_EXPORTS = {
|
|
34
|
+
# 문서 ingestion 프레임워크(임의 포맷 -> HWPX). 계약 유동.
|
|
35
|
+
"ConversionAttempt": "hwpx.ingest",
|
|
36
|
+
"DocumentConverter": "hwpx.ingest",
|
|
37
|
+
"DocumentIngestError": "hwpx.ingest",
|
|
38
|
+
"DocumentIngestResult": "hwpx.ingest",
|
|
39
|
+
"DocumentIngestor": "hwpx.ingest",
|
|
40
|
+
"DocumentSourceInfo": "hwpx.ingest",
|
|
41
|
+
"UnsupportedDocumentFormat": "hwpx.ingest",
|
|
42
|
+
# 레이아웃 프리뷰(한컴 없는 정직 근사). 계약 유동.
|
|
43
|
+
"LayoutPreview": "hwpx.tools.layout_preview",
|
|
44
|
+
"PreviewPage": "hwpx.tools.layout_preview",
|
|
45
|
+
"render_layout_preview": "hwpx.tools.layout_preview",
|
|
46
|
+
# 문서 프리뷰 뷰어(3.8.0 신규). 계약 유동.
|
|
47
|
+
"DocumentViewer": "hwpx.tools.document_viewer",
|
|
48
|
+
"render_document_viewer": "hwpx.tools.document_viewer",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_DEPRECATED_EXPORTS = {
|
|
52
|
+
"analyze_template_formfit": "hwpx.template_formfit",
|
|
53
|
+
"apply_template_formfit": "hwpx.template_formfit",
|
|
54
|
+
"TEMPLATE_FORMFIT_BASELINE_SCHEMA_VERSION": "hwpx.template_formfit",
|
|
55
|
+
"TEMPLATE_FORMFIT_PLAN_SCHEMA_VERSION": "hwpx.template_formfit",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# deprecated formfit 표면의 공통 대체 경로 안내.
|
|
59
|
+
_FORMFIT_REPLACEMENT = (
|
|
60
|
+
"구조적 form-fill 경로를 사용하세요: 라이브러리는 "
|
|
61
|
+
"hwpx.table_patch.fill_cells 계열, MCP는 analyze_form_fill/apply_form_fill/"
|
|
62
|
+
"verify_form_fill."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _experimental_message(name: str) -> str:
|
|
67
|
+
return (
|
|
68
|
+
f"'hwpx.{name}'는 실험적(experimental) 표면입니다. 계약이 유동적이므로 "
|
|
69
|
+
f"'from hwpx.experimental import {name}'로 import하세요. 최상위 재내보내기는 "
|
|
70
|
+
f"다음 major에서 제거될 예정입니다."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _deprecated_message(name: str) -> str:
|
|
75
|
+
return (
|
|
76
|
+
f"'hwpx.{name}'는 deprecated입니다. {_FORMFIT_REPLACEMENT} 이 이름은 "
|
|
77
|
+
f"다음 major에서 제거될 예정입니다."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
14
81
|
def __getattr__(name: str) -> object:
|
|
15
|
-
"""Resolve dynamic module attributes.
|
|
82
|
+
"""Resolve dynamic module attributes.
|
|
83
|
+
|
|
84
|
+
``__version__``은 경고 없이 지연 해석하고, experimental/deprecated 이름은
|
|
85
|
+
해석 시 ``DeprecationWarning``을 냅니다.
|
|
86
|
+
"""
|
|
16
87
|
|
|
17
88
|
if name == "__version__":
|
|
18
89
|
return _resolve_version()
|
|
90
|
+
|
|
91
|
+
module_name = _EXPERIMENTAL_EXPORTS.get(name)
|
|
92
|
+
if module_name is not None:
|
|
93
|
+
warnings.warn(_experimental_message(name), DeprecationWarning, stacklevel=2)
|
|
94
|
+
return getattr(importlib.import_module(module_name), name)
|
|
95
|
+
|
|
96
|
+
module_name = _DEPRECATED_EXPORTS.get(name)
|
|
97
|
+
if module_name is not None:
|
|
98
|
+
warnings.warn(_deprecated_message(name), DeprecationWarning, stacklevel=2)
|
|
99
|
+
return getattr(importlib.import_module(module_name), name)
|
|
100
|
+
|
|
19
101
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
20
102
|
|
|
103
|
+
|
|
104
|
+
def __dir__() -> list[str]:
|
|
105
|
+
return sorted(
|
|
106
|
+
set(globals())
|
|
107
|
+
| set(__all__)
|
|
108
|
+
| set(_EXPERIMENTAL_EXPORTS)
|
|
109
|
+
| set(_DEPRECATED_EXPORTS)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# --- stable 최상위 표면 (eager import) ------------------------------------------
|
|
21
114
|
from .tools.text_extractor import (
|
|
22
115
|
DEFAULT_NAMESPACES,
|
|
23
116
|
ParagraphInfo,
|
|
@@ -70,25 +163,8 @@ from .tools.style_profile import (
|
|
|
70
163
|
placeholder_fill_report,
|
|
71
164
|
register_template,
|
|
72
165
|
)
|
|
73
|
-
from .
|
|
74
|
-
|
|
75
|
-
PreviewPage,
|
|
76
|
-
render_layout_preview,
|
|
77
|
-
)
|
|
78
|
-
from .tools.document_viewer import (
|
|
79
|
-
DocumentViewer,
|
|
80
|
-
render_document_viewer,
|
|
81
|
-
)
|
|
82
|
-
from .ingest import (
|
|
83
|
-
ConversionAttempt,
|
|
84
|
-
DocumentConverter,
|
|
85
|
-
DocumentIngestError,
|
|
86
|
-
DocumentIngestResult,
|
|
87
|
-
DocumentIngestor,
|
|
88
|
-
DocumentSourceInfo,
|
|
89
|
-
HwpxMarkdownConverter,
|
|
90
|
-
UnsupportedDocumentFormat,
|
|
91
|
-
)
|
|
166
|
+
from .ingest import HwpxMarkdownConverter
|
|
167
|
+
from .errors import HwpxError
|
|
92
168
|
from .mutation_report import (
|
|
93
169
|
MutationReport,
|
|
94
170
|
PreservationDowngradeError,
|
|
@@ -124,12 +200,6 @@ from .quality import (
|
|
|
124
200
|
SavePipeline,
|
|
125
201
|
VisualCompleteReport,
|
|
126
202
|
)
|
|
127
|
-
from .template_formfit import (
|
|
128
|
-
TEMPLATE_FORMFIT_BASELINE_SCHEMA_VERSION,
|
|
129
|
-
TEMPLATE_FORMFIT_PLAN_SCHEMA_VERSION,
|
|
130
|
-
analyze_template_formfit,
|
|
131
|
-
apply_template_formfit,
|
|
132
|
-
)
|
|
133
203
|
|
|
134
204
|
__all__ = [
|
|
135
205
|
"QualityPolicy",
|
|
@@ -141,30 +211,21 @@ __all__ = [
|
|
|
141
211
|
"DEFAULT_STYLE_PRESET",
|
|
142
212
|
"DOCUMENT_PLAN_SCHEMA_VERSION",
|
|
143
213
|
"get_document_plan_schema",
|
|
144
|
-
"ConversionAttempt",
|
|
145
214
|
"DocumentBlock",
|
|
146
|
-
"DocumentConverter",
|
|
147
|
-
"DocumentIngestError",
|
|
148
|
-
"DocumentIngestResult",
|
|
149
|
-
"DocumentIngestor",
|
|
150
215
|
"DocumentPlan",
|
|
151
|
-
"DocumentSourceInfo",
|
|
152
216
|
"DocumentStylePreset",
|
|
153
217
|
"EditorOpenSafetyReport",
|
|
154
218
|
"ParagraphInfo",
|
|
155
219
|
"PackageValidationReport",
|
|
156
220
|
"BytePreservingPatchResult",
|
|
221
|
+
"HwpxError",
|
|
157
222
|
"MutationReport",
|
|
158
223
|
"PreservationDowngradeError",
|
|
159
224
|
"PlanValidationReport",
|
|
160
225
|
"ParagraphTextPatch",
|
|
161
226
|
"PatchApplied",
|
|
162
227
|
"PatchSkipped",
|
|
163
|
-
"LayoutPreview",
|
|
164
|
-
"PreviewPage",
|
|
165
228
|
"SectionInfo",
|
|
166
|
-
"TEMPLATE_FORMFIT_BASELINE_SCHEMA_VERSION",
|
|
167
|
-
"TEMPLATE_FORMFIT_PLAN_SCHEMA_VERSION",
|
|
168
229
|
"TextExtractor",
|
|
169
230
|
"FoundElement",
|
|
170
231
|
"HwpxMarkdownConverter",
|
|
@@ -177,7 +238,6 @@ __all__ = [
|
|
|
177
238
|
"STYLE_PROFILE_SCHEMA_VERSION",
|
|
178
239
|
"TEMPLATE_REGISTRY_SCHEMA_VERSION",
|
|
179
240
|
"TABLE_COMPUTE_REPORT_VERSION",
|
|
180
|
-
"UnsupportedDocumentFormat",
|
|
181
241
|
"apply_style_profile_to_plan",
|
|
182
242
|
"build_comparison_table_plan",
|
|
183
243
|
"build_image_grid",
|
|
@@ -190,8 +250,6 @@ __all__ = [
|
|
|
190
250
|
"HwpxDocument",
|
|
191
251
|
"HwpxPackage",
|
|
192
252
|
"create_document_from_plan",
|
|
193
|
-
"analyze_template_formfit",
|
|
194
|
-
"apply_template_formfit",
|
|
195
253
|
"approval_box",
|
|
196
254
|
"describe_template",
|
|
197
255
|
"extract_style_profile",
|
|
@@ -209,9 +267,6 @@ __all__ = [
|
|
|
209
267
|
"validate_editor_open_safety",
|
|
210
268
|
"validate_package",
|
|
211
269
|
"paragraph_patch",
|
|
212
|
-
"render_layout_preview",
|
|
213
|
-
"render_document_viewer",
|
|
214
|
-
"DocumentViewer",
|
|
215
270
|
"register_template",
|
|
216
271
|
"table_compute",
|
|
217
272
|
]
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import warnings
|
|
7
6
|
from os import PathLike
|
|
8
7
|
from typing import TYPE_CHECKING, Any, BinaryIO, Literal, Sequence
|
|
9
8
|
|
|
9
|
+
from ..errors import SaveError
|
|
10
10
|
from ..mutation_report import (
|
|
11
11
|
Fallback,
|
|
12
12
|
Mode,
|
|
@@ -84,7 +84,15 @@ def _run_pre_save_validation(doc: "HwpxDocument") -> None:
|
|
|
84
84
|
report = doc.validate()
|
|
85
85
|
if not report.ok:
|
|
86
86
|
msgs = _summarize_validation_issues(report.issues)
|
|
87
|
-
raise
|
|
87
|
+
raise SaveError(
|
|
88
|
+
f"Document validation failed: {msgs}",
|
|
89
|
+
code="document-validation-failed",
|
|
90
|
+
context={"issueCount": len(report.issues), "issues": msgs},
|
|
91
|
+
suggestion=(
|
|
92
|
+
"Fix the reported schema issues, or disable validate_on_save if "
|
|
93
|
+
"the validation is a false positive for your document."
|
|
94
|
+
),
|
|
95
|
+
)
|
|
88
96
|
|
|
89
97
|
|
|
90
98
|
def _run_open_safety_validation(doc: "HwpxDocument", archive_bytes: bytes) -> None:
|
|
@@ -94,9 +102,15 @@ def _run_open_safety_validation(doc: "HwpxDocument", archive_bytes: bytes) -> No
|
|
|
94
102
|
|
|
95
103
|
report = validate_editor_open_safety(archive_bytes)
|
|
96
104
|
if not report.ok:
|
|
97
|
-
raise
|
|
105
|
+
raise SaveError(
|
|
98
106
|
"Generated HWPX package failed open-safety validation: "
|
|
99
|
-
+ report.summary
|
|
107
|
+
+ report.summary,
|
|
108
|
+
code="open-safety-failed",
|
|
109
|
+
context={"summary": report.summary},
|
|
110
|
+
suggestion=(
|
|
111
|
+
"The serialized package would not reopen in an HWPX editor; "
|
|
112
|
+
"inspect validate_editor_open_safety(...) for the failing checks."
|
|
113
|
+
),
|
|
100
114
|
)
|
|
101
115
|
|
|
102
116
|
|
|
@@ -126,7 +140,15 @@ def _gate_and_write(
|
|
|
126
140
|
)
|
|
127
141
|
if not report.ok:
|
|
128
142
|
detail = "; ".join(str(error) for error in report.errors)
|
|
129
|
-
raise
|
|
143
|
+
raise SaveError(
|
|
144
|
+
f"Document save failed the quality gate: {detail}",
|
|
145
|
+
code="quality-gate-failed",
|
|
146
|
+
context={"errors": [str(error) for error in report.errors]},
|
|
147
|
+
suggestion=(
|
|
148
|
+
"The SavePipeline quality gate rejected the archive; inspect the "
|
|
149
|
+
"returned report's errors before retrying."
|
|
150
|
+
),
|
|
151
|
+
)
|
|
130
152
|
return report
|
|
131
153
|
|
|
132
154
|
|
|
@@ -420,29 +442,3 @@ def _mark_save_clean(doc: "HwpxDocument") -> None:
|
|
|
420
442
|
package = doc._package
|
|
421
443
|
package._opened_members = dict(package._files)
|
|
422
444
|
package._opened_zip_infos = dict(package._zip_infos)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
def save(
|
|
426
|
-
doc: "HwpxDocument",
|
|
427
|
-
path_or_stream: str | PathLike[str] | BinaryIO | None = None,
|
|
428
|
-
) -> str | PathLike[str] | BinaryIO | bytes:
|
|
429
|
-
"""Deprecated compatibility wrapper around save_to_path/save_to_stream/to_bytes.
|
|
430
|
-
|
|
431
|
-
Deprecated:
|
|
432
|
-
``save()``는 하위 호환을 위해 유지되며 향후 제거될 수 있습니다.
|
|
433
|
-
- 경로 저장: ``save_to_path(path)``
|
|
434
|
-
- 스트림 저장: ``save_to_stream(stream)``
|
|
435
|
-
- 바이트 반환: ``to_bytes()``
|
|
436
|
-
"""
|
|
437
|
-
|
|
438
|
-
warnings.warn(
|
|
439
|
-
"HwpxDocument.save()는 deprecated 예정입니다. "
|
|
440
|
-
"save_to_path()/save_to_stream()/to_bytes() 사용을 권장합니다.",
|
|
441
|
-
DeprecationWarning,
|
|
442
|
-
stacklevel=2,
|
|
443
|
-
)
|
|
444
|
-
if path_or_stream is None:
|
|
445
|
-
return doc.to_bytes()
|
|
446
|
-
if isinstance(path_or_stream, (str, PathLike)):
|
|
447
|
-
return doc.save_to_path(path_or_stream)
|
|
448
|
-
return doc.save_to_stream(path_or_stream)
|
|
@@ -1844,28 +1844,3 @@ class HwpxDocument:
|
|
|
1844
1844
|
self,
|
|
1845
1845
|
reset_dirty=reset_dirty,
|
|
1846
1846
|
)
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
@overload
|
|
1850
|
-
def save(self, path_or_stream: None = None) -> bytes: ...
|
|
1851
|
-
|
|
1852
|
-
@overload
|
|
1853
|
-
def save(self, path_or_stream: str | PathLike[str]) -> str | PathLike[str]: ...
|
|
1854
|
-
|
|
1855
|
-
@overload
|
|
1856
|
-
def save(self, path_or_stream: BinaryIO) -> BinaryIO: ...
|
|
1857
|
-
|
|
1858
|
-
def save(
|
|
1859
|
-
self,
|
|
1860
|
-
path_or_stream: str | PathLike[str] | BinaryIO | None = None,
|
|
1861
|
-
) -> str | PathLike[str] | BinaryIO | bytes:
|
|
1862
|
-
"""Deprecated compatibility wrapper around save_to_path/save_to_stream/to_bytes.
|
|
1863
|
-
|
|
1864
|
-
Deprecated:
|
|
1865
|
-
``save()``는 하위 호환을 위해 유지되며 향후 제거될 수 있습니다.
|
|
1866
|
-
- 경로 저장: ``save_to_path(path)``
|
|
1867
|
-
- 스트림 저장: ``save_to_stream(stream)``
|
|
1868
|
-
- 바이트 반환: ``to_bytes()``
|
|
1869
|
-
"""
|
|
1870
|
-
|
|
1871
|
-
return _persistence.save(self, path_or_stream=path_or_stream)
|