python-hwpx-automation 7.3.2__tar.gz → 7.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_hwpx_automation-7.3.2/src/python_hwpx_automation.egg-info → python_hwpx_automation-7.3.3}/PKG-INFO +3 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/README.md +2 -2
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/pyproject.toml +1 -1
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/content.py +18 -2
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/document.py +2 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/transactions.py +15 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/errors.py +54 -1
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/agent_document.py +5 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/read_export.py +14 -10
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/identity.json +2 -2
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/mixed_form.py +3 -1
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/oracle.py +15 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/context.py +49 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/form_fields.py +3 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/package_validation.py +1 -1
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/planning.py +1 -1
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/read_query.py +21 -16
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/save_policy.py +3 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/transactions.py +1 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/runtime.py +26 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/storage.py +116 -10
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/upstream.py +56 -2
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3/src/python_hwpx_automation.egg-info}/PKG-INFO +3 -3
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/LICENSE +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/MANIFEST.in +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/NOTICE +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/setup.cfg +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/__init__.pyi +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/__main__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/agent_document.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/api.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/blind_eval.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/capabilities.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/compat.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/configuration.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/context.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/diff.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/formatting.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/handles.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/locations.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/locator.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/plan.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/resources.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/search.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/txn.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/document_state.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/execution_lock.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/fastmcp_adapter.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/form_fill.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/form_output_models.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/_shared.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/authoring.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/content_edit.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/form_fill.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/layout_style.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/quality_render.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/specialized.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/tracked_changes.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/handlers/workflow.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/hwp_converter.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/hwp_support.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/hwpx_ops.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/identity.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ingest_adapters.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/markdown_plan.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/mcp_cli.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/metadata/tools_meta.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/mutation_models.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/network_policy.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/_batch_publication.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/_batch_verification.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/_text_scope.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/bundle.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/catalog.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/dump.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/mapping.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/model.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/native.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/blueprint/replay.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/catalog.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/cli.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/commands.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/document.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/form_plan.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/model.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/path.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/query.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/agent/story.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/advanced_generators.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/builder/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/builder/core.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/builder/report.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/_support.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/composer.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/harvest.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/plan.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profile.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/profile.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/profile.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/design/validator.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/presets/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/presets/proposal.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/report_parser.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/style_profile.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/authoring/template_analyzer.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/charting/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/compliance/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/compliance/official_lint.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/compliance/pii.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/document_ops/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/document_ops/comparison.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/document_ops/mail_merge.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/document_ops/redline.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/evalplan/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/evalplan/runtime.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/compose.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/ir.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/measure.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/parser.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/exam/profile.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/classification.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fill_residue.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/apply.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/engine.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/measure.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/policy.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/report.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/seal.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/fit/wordbox.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/guidance.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/quality.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/split_run.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/form_fill/template_formfit.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/composition.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/data/bank.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/data/genres.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/gianmun.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/house_style/org_chart.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/quality/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/quality/page_guard.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/__main__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/_hancom_open_rate.ps1 +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/_render_hwpx.ps1 +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/_render_hwpx_mac.applescript +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/block_splits.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/cli.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/detectors.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/diff.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/fixture_corpus.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/mac_session.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/page_qa.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/qa_contracts.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/qa_metrics.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/rendering/worker.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/utilities/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/office/utilities/table_compute.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/_border_fill.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/composition.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/content_layout.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/media.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/memo_style.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/preview_export.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/ops_services/tables.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/preview_output_models.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/public-modules.json +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/py.typed +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/quality.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/quality_generation.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/resources.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/runtime_services.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/server.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/tool_bindings.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/tool_contract.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/utils/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/utils/helpers.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/utils/read_budget.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/visual_qa.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/__init__.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/adapters.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/dispatcher.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/evidence_lineage.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/models.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/policy.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/render_contracts.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/render_metrics.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/render_queue.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/render_security.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/render_transport.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/rendering.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/service.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/state_machine.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workflow/store.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/workspace.py +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/python_hwpx_automation.egg-info/SOURCES.txt +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/python_hwpx_automation.egg-info/dependency_links.txt +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/python_hwpx_automation.egg-info/entry_points.txt +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/python_hwpx_automation.egg-info/requires.txt +0 -0
- {python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/python_hwpx_automation.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-hwpx-automation
|
|
3
|
-
Version: 7.3.
|
|
3
|
+
Version: 7.3.3
|
|
4
4
|
Summary: Task-oriented HWPX document automation for Python, with an optional MCP adapter.
|
|
5
5
|
Author: Kohkyuhyun
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -74,7 +74,7 @@ Dynamic: license-file
|
|
|
74
74
|
|
|
75
75
|
<!-- release-state: release-approved -->
|
|
76
76
|
> [!NOTE]
|
|
77
|
-
> 발행이 승인된 7.3.
|
|
77
|
+
> 발행이 승인된 7.3.3 후보 (release-approved; 원격 발행 대기): `python-hwpx 6.6.0 → python-hwpx-automation 7.3.3 → hwpx-plugin 2.4.0` (`5e5c23651f92785a`).
|
|
78
78
|
> 공개 트레인: `python-hwpx 6.6.0 → python-hwpx-automation 7.3.1 → hwpx-plugin 2.4.0`.
|
|
79
79
|
> 공개 좌표는 core·automation PyPI와 plugin GitHub
|
|
80
80
|
> Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
|
|
@@ -162,7 +162,7 @@ PDF와 쪽 PNG로 렌더합니다. 별도 환경에서 실행하므로 호출하
|
|
|
162
162
|
고정 버전을 건드리지 않습니다.
|
|
163
163
|
|
|
164
164
|
```bash
|
|
165
|
-
uvx --from "python-hwpx-automation[oracle]==7.3.
|
|
165
|
+
uvx --from "python-hwpx-automation[oracle]==7.3.3" \
|
|
166
166
|
hwpx render-pdf in.hwpx out.pdf --png out/page --json
|
|
167
167
|
```
|
|
168
168
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
<!-- release-state: release-approved -->
|
|
16
16
|
> [!NOTE]
|
|
17
|
-
> 발행이 승인된 7.3.
|
|
17
|
+
> 발행이 승인된 7.3.3 후보 (release-approved; 원격 발행 대기): `python-hwpx 6.6.0 → python-hwpx-automation 7.3.3 → hwpx-plugin 2.4.0` (`5e5c23651f92785a`).
|
|
18
18
|
> 공개 트레인: `python-hwpx 6.6.0 → python-hwpx-automation 7.3.1 → hwpx-plugin 2.4.0`.
|
|
19
19
|
> 공개 좌표는 core·automation PyPI와 plugin GitHub
|
|
20
20
|
> Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
|
|
@@ -102,7 +102,7 @@ PDF와 쪽 PNG로 렌더합니다. 별도 환경에서 실행하므로 호출하
|
|
|
102
102
|
고정 버전을 건드리지 않습니다.
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
|
-
uvx --from "python-hwpx-automation[oracle]==7.3.
|
|
105
|
+
uvx --from "python-hwpx-automation[oracle]==7.3.3" \
|
|
106
106
|
hwpx render-pdf in.hwpx out.pdf --png out/page --json
|
|
107
107
|
```
|
|
108
108
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-hwpx-automation"
|
|
7
|
-
version = "7.3.
|
|
7
|
+
version = "7.3.3"
|
|
8
8
|
description = "Task-oriented HWPX document automation for Python, with an optional MCP adapter."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Kohkyuhyun" }]
|
{python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/content.py
RENAMED
|
@@ -14,8 +14,15 @@ from uuid import uuid4
|
|
|
14
14
|
from xml.etree import ElementTree as ET
|
|
15
15
|
|
|
16
16
|
from ..compat import patch_python_hwpx
|
|
17
|
-
from ..storage import build_hwpx_open_safety_report
|
|
18
|
-
from ..upstream import
|
|
17
|
+
from ..storage import build_hwpx_open_safety_report, open_local_document
|
|
18
|
+
from ..upstream import (
|
|
19
|
+
HP_NS as _HP_NS,
|
|
20
|
+
HwpxDocument,
|
|
21
|
+
is_hwp5_source,
|
|
22
|
+
is_hwp5_target,
|
|
23
|
+
repair_pathological_text_spacing,
|
|
24
|
+
)
|
|
25
|
+
from .document import save_doc
|
|
19
26
|
from .formatting import resolve_style_id
|
|
20
27
|
from .locations import resolve_paragraph_reference
|
|
21
28
|
|
|
@@ -500,6 +507,15 @@ def copy_document_file(source: str, destination: str = None) -> str:
|
|
|
500
507
|
destination = f"{stem}_copy.{ext}"
|
|
501
508
|
source_path = Path(source)
|
|
502
509
|
destination_path = Path(destination)
|
|
510
|
+
if is_hwp5_source(source_path) != is_hwp5_target(destination_path):
|
|
511
|
+
# The destination extension picks the format, so a copy between .hwp
|
|
512
|
+
# and .hwpx is written through the document model, not byte-copied.
|
|
513
|
+
document = open_local_document(source_path, role="copy source")
|
|
514
|
+
try:
|
|
515
|
+
save_doc(document, str(destination_path))
|
|
516
|
+
finally:
|
|
517
|
+
document.close()
|
|
518
|
+
return str(destination_path)
|
|
503
519
|
if source_path.suffix.lower() != ".hwpx" and destination_path.suffix.lower() != ".hwpx":
|
|
504
520
|
shutil.copy2(source_path, destination_path)
|
|
505
521
|
return str(destination_path)
|
{python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/core/document.py
RENAMED
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from ..configuration import env_value
|
|
8
|
-
from ..storage import LocalDocumentStorage,
|
|
8
|
+
from ..storage import LocalDocumentStorage, open_local_document
|
|
9
9
|
from ..upstream import HwpxDocument, blank_document_template_bytes, open_document
|
|
10
10
|
|
|
11
11
|
|
|
@@ -18,8 +18,7 @@ def _local_storage() -> LocalDocumentStorage:
|
|
|
18
18
|
def open_doc(path: str) -> HwpxDocument:
|
|
19
19
|
if not os.path.exists(path):
|
|
20
20
|
raise FileNotFoundError(f"파일을 찾을 수 없습니다: {path}")
|
|
21
|
-
|
|
22
|
-
return open_document(path)
|
|
21
|
+
return open_local_document(Path(path), role="local HWPX open")
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
def save_doc(doc: HwpxDocument, path: str, *, quality: Any = None) -> dict[str, Any]:
|
|
@@ -12,8 +12,12 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any, Iterable
|
|
13
13
|
|
|
14
14
|
from .. import quality as quality_contract
|
|
15
|
-
from ..storage import
|
|
16
|
-
|
|
15
|
+
from ..storage import (
|
|
16
|
+
build_hwpx_verification_report,
|
|
17
|
+
require_hwpx_editor_open_safe,
|
|
18
|
+
require_native_hwp5,
|
|
19
|
+
)
|
|
20
|
+
from ..upstream import HwpxDocument, hwp5_document_bytes, is_hwp5_target, open_document
|
|
17
21
|
|
|
18
22
|
_MAX_SUMMARY_ITEMS = 20
|
|
19
23
|
_MAX_SNIPPET = 80
|
|
@@ -341,9 +345,13 @@ def save_dry_run(
|
|
|
341
345
|
document: HwpxDocument, target: str | Path, *, quality: Any = None
|
|
342
346
|
) -> dict[str, Any]:
|
|
343
347
|
target_path = Path(target)
|
|
348
|
+
hwp_target = is_hwp5_target(target_path)
|
|
349
|
+
if hwp_target:
|
|
350
|
+
require_native_hwp5()
|
|
351
|
+
# The gate checks HWPX parts, so an .hwp target is staged as HWPX.
|
|
344
352
|
fd, tmp_name = tempfile.mkstemp(
|
|
345
353
|
prefix=f".{target_path.stem}.dry-run.",
|
|
346
|
-
suffix=target_path.suffix or ".hwpx",
|
|
354
|
+
suffix=".hwpx" if hwp_target else (target_path.suffix or ".hwpx"),
|
|
347
355
|
dir=str(target_path.parent),
|
|
348
356
|
)
|
|
349
357
|
tmp_path = Path(tmp_name)
|
|
@@ -366,6 +374,10 @@ def save_dry_run(
|
|
|
366
374
|
"dry-run HWPX failed open-safety verification: "
|
|
367
375
|
+ verification["openSafety"]["summary"]
|
|
368
376
|
)
|
|
377
|
+
if hwp_target:
|
|
378
|
+
# Raises Hwp5Error (hwp5-write-unsupported) as the real save would.
|
|
379
|
+
hwp5_document_bytes(document)
|
|
380
|
+
verification["format"] = "hwp"
|
|
369
381
|
diff = semantic_diff(target_path, tmp_path) if target_path.exists() else None
|
|
370
382
|
verification["filePath"] = str(target_path)
|
|
371
383
|
verification["dryRunTempDeleted"] = True
|
|
@@ -73,6 +73,7 @@ DEFAULT_ERROR_SUGGESTIONS: dict[str, str] = {
|
|
|
73
73
|
"EMPTY_MATCH": "찾을 텍스트나 앵커 조건을 실제 문서 내용에 맞게 수정하세요.",
|
|
74
74
|
"HWP_CONVERSION_FAILED": "원본 HWP가 손상되지 않았는지 확인하고 변환 로그의 원인을 기준으로 다시 시도하세요.",
|
|
75
75
|
"HWP_TEXT_EXTRACT_FAILED": "HWP 파일을 다른 뷰어에서 열어 유효성을 확인한 뒤 텍스트 추출을 다시 실행하세요.",
|
|
76
|
+
"HWPX_PACKAGE_REQUIRED": "copy_document로 .hwpx 사본을 만들어 이 도구를 쓰고, .hwp가 필요하면 결과를 copy_document로 .hwp 경로에 복사하세요. search_and_replace·set_table_cell_text 같은 문서 편집 도구는 .hwp를 그대로 편집합니다.",
|
|
76
77
|
"IDEMPOTENT_REPLAY": "이미 적용된 planId입니다. 최신 preview/plan을 새로 만든 뒤 apply를 다시 호출하세요.",
|
|
77
78
|
"MEMO_NOT_FOUND": "list_memos 또는 문서 리소스에서 memoId를 다시 확인한 뒤 호출하세요.",
|
|
78
79
|
"MISSING_NODE": "대상 섹션, 문단, 표, 셀이 아직 존재하는지 조회한 뒤 새 앵커로 다시 실행하세요.",
|
|
@@ -81,7 +82,10 @@ DEFAULT_ERROR_SUGGESTIONS: dict[str, str] = {
|
|
|
81
82
|
"PIPELINE_ERROR": "details.pipelineCode와 hint를 확인한 뒤 preview부터 다시 생성하세요.",
|
|
82
83
|
"PLAN_RECORD_MISSING": "preview_edit 또는 plan_edit으로 planId를 새로 발급받은 뒤 apply를 다시 호출하세요.",
|
|
83
84
|
"PREVIEW_REQUIRED": "preview_edit으로 변경 내용을 확인한 뒤 반환된 planId로 apply_edit을 호출하세요.",
|
|
84
|
-
"
|
|
85
|
+
"HWP_DOCUMENT_UNREADABLE": "한/글에서 문서를 열어 다시 저장한 뒤 사용하세요. details.hwp5Code가 원인입니다.",
|
|
86
|
+
"HWP_ENCRYPTED_DOCUMENT": "한/글에서 문서 암호·배포용 보호를 풀고 다시 저장한 뒤 사용하세요. DRM 문서는 열 수 없습니다.",
|
|
87
|
+
"HWP_WRITE_UNSUPPORTED": "HWP 5.0으로 쓸 수 없는 내용이 있습니다. 출력 경로를 .hwpx로 지정해 저장하세요.",
|
|
88
|
+
"READ_ONLY_HWP_DOCUMENT": "python-hwpx 6.6.0 이상을 설치하면 .hwp 문서를 그대로 열고 편집·저장할 수 있습니다.",
|
|
85
89
|
"RENDER_PREVIEW_INVALID_MODE": "mode는 'pages' 또는 'long'으로 지정한 뒤 다시 실행하세요.",
|
|
86
90
|
"RENDER_PREVIEW_INVALID_SCREENSHOT_MODE": "screenshot은 'auto', 'require', 'off' 중 하나로 지정하세요.",
|
|
87
91
|
"RENDER_PREVIEW_UNAVAILABLE": "matching python-hwpx 버전을 설치하고 MCP 서버를 새로 시작한 뒤 다시 실행하세요.",
|
|
@@ -175,3 +179,52 @@ def build_error_payload(
|
|
|
175
179
|
suggestion=suggestion
|
|
176
180
|
or suggestion_for_error(code, details=details, hint=hint),
|
|
177
181
|
).model_dump(exclude_none=True, by_alias=True)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class HwpDocumentError(RuntimeError):
|
|
185
|
+
"""An ``.hwp`` request the installed engine cannot carry out."""
|
|
186
|
+
|
|
187
|
+
def __init__(
|
|
188
|
+
self, message: str, *, code: str, details: Optional[Dict[str, Any]] = None
|
|
189
|
+
) -> None:
|
|
190
|
+
super().__init__(message)
|
|
191
|
+
self.code = code
|
|
192
|
+
self.message = message
|
|
193
|
+
self.details = details
|
|
194
|
+
|
|
195
|
+
def to_payload(self) -> Dict[str, Any]:
|
|
196
|
+
return build_error_payload(
|
|
197
|
+
code=self.code, message=self.message, details=self.details
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
_HWP5_ENCRYPTED_CODES = frozenset({"hwp5-password", "hwp5-distribution", "hwp5-drm"})
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def hwp5_error_payload(exc: BaseException) -> Optional[Dict[str, Any]]:
|
|
205
|
+
"""The MCP error for python-hwpx's ``Hwp5Error``; None for any other exception.
|
|
206
|
+
|
|
207
|
+
Matched by its ``hwp5-*`` code so this module needs no core import.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
hwp5_code = getattr(exc, "code", None)
|
|
211
|
+
if not isinstance(hwp5_code, str) or not hwp5_code.startswith("hwp5-"):
|
|
212
|
+
return None
|
|
213
|
+
details = {"hwp5Code": hwp5_code}
|
|
214
|
+
if hwp5_code == "hwp5-write-unsupported":
|
|
215
|
+
return build_error_payload(
|
|
216
|
+
code="HWP_WRITE_UNSUPPORTED",
|
|
217
|
+
message="문서에 HWP 5.0(.hwp)으로 쓸 수 없는 내용이 있어 아무것도 저장하지 않았습니다.",
|
|
218
|
+
details=details,
|
|
219
|
+
)
|
|
220
|
+
if hwp5_code in _HWP5_ENCRYPTED_CODES:
|
|
221
|
+
return build_error_payload(
|
|
222
|
+
code="HWP_ENCRYPTED_DOCUMENT",
|
|
223
|
+
message="암호·배포용·DRM으로 보호된 HWP 문서는 열 수 없습니다.",
|
|
224
|
+
details=details,
|
|
225
|
+
)
|
|
226
|
+
return build_error_payload(
|
|
227
|
+
code="HWP_DOCUMENT_UNREADABLE",
|
|
228
|
+
message="HWP 5.0(.hwp) 문서를 읽을 수 없습니다.",
|
|
229
|
+
details=details,
|
|
230
|
+
)
|
|
@@ -9,6 +9,8 @@ from typing import Any
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
from ..document_state import document_state_payload
|
|
12
|
+
from ..errors import HwpDocumentError
|
|
13
|
+
from ..storage import require_hwpx_package
|
|
12
14
|
from ..agent_document import (
|
|
13
15
|
AgentChildLimit,
|
|
14
16
|
AgentCommandList,
|
|
@@ -100,6 +102,7 @@ def apply_document_commands(
|
|
|
100
102
|
try:
|
|
101
103
|
resolved_input = resolve_path(filename)
|
|
102
104
|
resolved_output = resolve_path(output)
|
|
105
|
+
require_hwpx_package(resolved_input, output=resolved_output)
|
|
103
106
|
quality_contract.assert_write_capability()
|
|
104
107
|
store = ScopedIdempotencyStore(
|
|
105
108
|
RUNTIME_SERVICES.idempotency_cache,
|
|
@@ -132,6 +135,8 @@ def apply_document_commands(
|
|
|
132
135
|
if Path(state_path).exists():
|
|
133
136
|
payload.update(document_state_payload(state_path))
|
|
134
137
|
return payload
|
|
138
|
+
except HwpDocumentError:
|
|
139
|
+
raise
|
|
135
140
|
except Exception as exc:
|
|
136
141
|
return agent_batch_error_payload(
|
|
137
142
|
exc,
|
|
@@ -35,6 +35,7 @@ from ..office.compliance import DEFAULT_POLICY, mask_pii
|
|
|
35
35
|
from ..runtime_services import RUNTIME_SERVICES
|
|
36
36
|
from ..upstream import (
|
|
37
37
|
HP_NS,
|
|
38
|
+
hwp5_conversion_report,
|
|
38
39
|
open_document,
|
|
39
40
|
)
|
|
40
41
|
from ..utils.helpers import default_max_chars, resolve_path, truncate_response
|
|
@@ -777,16 +778,19 @@ def get_document_info(filename: str) -> dict:
|
|
|
777
778
|
path = resolve_path(filename)
|
|
778
779
|
doc = open_doc(path)
|
|
779
780
|
file_size = Path(path).stat().st_size
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
781
|
+
info: dict[str, Any] = {
|
|
782
|
+
"filename": filename,
|
|
783
|
+
"sections": len(doc.sections),
|
|
784
|
+
"paragraphs": _paragraph_count(doc),
|
|
785
|
+
"tables": _table_count(doc),
|
|
786
|
+
"file_size": str(file_size),
|
|
787
|
+
}
|
|
788
|
+
conversion = hwp5_conversion_report(doc)
|
|
789
|
+
if conversion is not None:
|
|
790
|
+
# An .hwp is edited through the document model; this is what it left out.
|
|
791
|
+
info["format"] = "hwp"
|
|
792
|
+
info["hwpConversion"] = conversion
|
|
793
|
+
return _with_document_state(info, path)
|
|
790
794
|
|
|
791
795
|
|
|
792
796
|
def get_document_text(
|
{python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/identity.json
RENAMED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"candidate": {
|
|
8
8
|
"pythonHwpx": "6.6.0",
|
|
9
9
|
"canonicalDistribution": "python-hwpx-automation",
|
|
10
|
-
"canonicalAutomation": "7.3.
|
|
10
|
+
"canonicalAutomation": "7.3.3",
|
|
11
11
|
"compatibilityDistribution": "hwpx-mcp-server",
|
|
12
|
-
"compatibility": "7.3.
|
|
12
|
+
"compatibility": "7.3.3",
|
|
13
13
|
"plugin": "2.4.0",
|
|
14
14
|
"contractHash": "5e5c23651f92785a"
|
|
15
15
|
},
|
{python_hwpx_automation-7.3.2 → python_hwpx_automation-7.3.3}/src/hwpx_automation/mixed_form.py
RENAMED
|
@@ -41,7 +41,7 @@ from pydantic import (
|
|
|
41
41
|
from .execution_lock import PUBLIC_MUTATION_LOCK
|
|
42
42
|
from .office.agent._batch_publication import GuardedSavePipeline
|
|
43
43
|
from .office.rendering import resolve_hancom_backend
|
|
44
|
-
from .storage import build_hwpx_open_safety_report
|
|
44
|
+
from .storage import build_hwpx_open_safety_report, require_hwpx_package
|
|
45
45
|
from .utils.helpers import resolve_path
|
|
46
46
|
from .workspace import (
|
|
47
47
|
WorkspaceMissingParentGuard,
|
|
@@ -1374,6 +1374,7 @@ def analyze_mixed_form_plan(
|
|
|
1374
1374
|
|
|
1375
1375
|
request = _authorize_public_plan(_payload(plan, apply=False))
|
|
1376
1376
|
source = Path(request["source"])
|
|
1377
|
+
require_hwpx_package(source, output=request["output"])
|
|
1377
1378
|
source_snapshot = _capture_path_snapshot(source)
|
|
1378
1379
|
if source_snapshot.data is None:
|
|
1379
1380
|
raise FileNotFoundError(source)
|
|
@@ -1494,6 +1495,7 @@ def _apply_canonical_mixed_form_plan_locked(
|
|
|
1494
1495
|
|
|
1495
1496
|
compiled = validate_mixed_form_plan(compiled).to_dict()
|
|
1496
1497
|
source, output = _authorize_compiled_plan(compiled)
|
|
1498
|
+
require_hwpx_package(source, output=output)
|
|
1497
1499
|
source_snapshot = _capture_path_snapshot(source)
|
|
1498
1500
|
if source_snapshot.data is None: # pragma: no cover - compiled plan invariant
|
|
1499
1501
|
raise FileNotFoundError(source)
|
|
@@ -149,6 +149,16 @@ def _complete_package(path: str) -> bool:
|
|
|
149
149
|
return False
|
|
150
150
|
|
|
151
151
|
|
|
152
|
+
def _unchanged(path: str, before: os.stat_result) -> bool:
|
|
153
|
+
"""True when ``path`` still has the size and modification time in ``before``."""
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
now = os.stat(path)
|
|
157
|
+
except OSError:
|
|
158
|
+
return False
|
|
159
|
+
return (now.st_size, now.st_mtime_ns) == (before.st_size, before.st_mtime_ns)
|
|
160
|
+
|
|
161
|
+
|
|
152
162
|
def _promote_file(staged: str, target: str) -> None:
|
|
153
163
|
"""Move a finished file to ``target`` without leaving a partial ``target``.
|
|
154
164
|
|
|
@@ -442,6 +452,8 @@ class WindowsComOracle(RenderBackend):
|
|
|
442
452
|
by a complete package: a failed refresh leaves it as it was. Returns
|
|
443
453
|
True when the file was re-saved. Only an ``.hwpx`` file is refreshed
|
|
444
454
|
(Hancom saves it as HWPX), and a link is followed to the file it names.
|
|
455
|
+
A document that changed while Hancom ran (size or modification time)
|
|
456
|
+
is not overwritten: the refresh returns False and the change stays.
|
|
445
457
|
"""
|
|
446
458
|
|
|
447
459
|
src = os.path.realpath(hwpx_path)
|
|
@@ -459,6 +471,7 @@ class WindowsComOracle(RenderBackend):
|
|
|
459
471
|
try:
|
|
460
472
|
os.makedirs(os.path.dirname(job_src))
|
|
461
473
|
os.makedirs(os.path.dirname(job_out))
|
|
474
|
+
before = os.stat(src)
|
|
462
475
|
shutil.copyfile(src, job_src)
|
|
463
476
|
except OSError:
|
|
464
477
|
return False
|
|
@@ -467,6 +480,8 @@ class WindowsComOracle(RenderBackend):
|
|
|
467
480
|
entry = entries[0] if entries else None
|
|
468
481
|
if not (isinstance(entry, dict) and entry.get("saved") and _complete_package(job_out)):
|
|
469
482
|
return False
|
|
483
|
+
if not _unchanged(src, before):
|
|
484
|
+
return False
|
|
470
485
|
try:
|
|
471
486
|
_promote_file(job_out, src)
|
|
472
487
|
except OSError:
|
|
@@ -4,13 +4,16 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
6
|
import logging
|
|
7
|
+
from io import BytesIO
|
|
7
8
|
from pathlib import Path
|
|
9
|
+
from zipfile import ZipFile
|
|
8
10
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
9
11
|
|
|
12
|
+
from ..errors import HwpDocumentError, hwp5_error_payload
|
|
10
13
|
from ..hwp_support import HwpBinaryError, extract_hwp_text
|
|
11
14
|
from ..core.locator import RegisteredHandle
|
|
12
15
|
from ..core.context import default_session_lifecycle_policy
|
|
13
|
-
from ..storage import DocumentStorage, LocalDocumentStorage
|
|
16
|
+
from ..storage import DocumentStorage, LocalDocumentStorage, require_hwpx_package
|
|
14
17
|
from ..workspace import (
|
|
15
18
|
WorkspacePathError,
|
|
16
19
|
)
|
|
@@ -18,6 +21,8 @@ from ..upstream import (
|
|
|
18
21
|
HwpxDocument,
|
|
19
22
|
HwpxOxmlParagraph,
|
|
20
23
|
HwpxOxmlTable,
|
|
24
|
+
hwpx_view_bytes,
|
|
25
|
+
native_hwp5_supported,
|
|
21
26
|
)
|
|
22
27
|
|
|
23
28
|
logger = logging.getLogger("hwpx_automation.hwpx_ops")
|
|
@@ -158,12 +163,50 @@ class DocumentContext:
|
|
|
158
163
|
def _relative_path(self, path: Path) -> str:
|
|
159
164
|
return self.storage.relative_path(path)
|
|
160
165
|
|
|
166
|
+
def _is_legacy_hwp(self, resolved: Path) -> bool:
|
|
167
|
+
"""An ``.hwp`` the installed core cannot open; only its preview text is readable."""
|
|
168
|
+
|
|
169
|
+
return resolved.suffix.lower() == ".hwp" and not native_hwp5_supported()
|
|
170
|
+
|
|
171
|
+
def _text_source(self, resolved: Path) -> Path | ZipFile:
|
|
172
|
+
"""What the text extractor reads: the HWPX file, or an ``.hwp``'s HWPX model."""
|
|
173
|
+
|
|
174
|
+
if resolved.suffix.lower() != ".hwp":
|
|
175
|
+
return resolved
|
|
176
|
+
try:
|
|
177
|
+
return ZipFile(BytesIO(hwpx_view_bytes(resolved)))
|
|
178
|
+
except Exception as exc:
|
|
179
|
+
hwp_error = self._hwp_error(exc)
|
|
180
|
+
if hwp_error is None:
|
|
181
|
+
raise
|
|
182
|
+
raise hwp_error from exc
|
|
183
|
+
|
|
184
|
+
def _hwp_error(self, exc: BaseException) -> Optional[RuntimeError]:
|
|
185
|
+
"""The operation error for an ``.hwp`` refusal, or None for any other failure."""
|
|
186
|
+
|
|
187
|
+
if isinstance(exc, HwpDocumentError):
|
|
188
|
+
return self._new_error(exc.code, exc.message, details=exc.details)
|
|
189
|
+
payload = hwp5_error_payload(exc)
|
|
190
|
+
if payload is None:
|
|
191
|
+
return None
|
|
192
|
+
return self._new_error(
|
|
193
|
+
payload["code"], payload["message"], details=payload.get("details")
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
def _require_hwpx_package(self, source: Path, output: Optional[str] = None) -> None:
|
|
197
|
+
"""Refuse ``.hwp`` for editors that patch HWPX package bytes."""
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
require_hwpx_package(source, output=output)
|
|
201
|
+
except HwpDocumentError as exc:
|
|
202
|
+
raise self._new_error(exc.code, exc.message, details=exc.details) from exc
|
|
203
|
+
|
|
161
204
|
def _open_document(self, path: str) -> Tuple[HwpxDocument, Path]:
|
|
162
205
|
resolved = self._resolve_path(path)
|
|
163
|
-
if
|
|
206
|
+
if self._is_legacy_hwp(resolved):
|
|
164
207
|
raise self._new_error(
|
|
165
208
|
"READ_ONLY_HWP_DOCUMENT",
|
|
166
|
-
"
|
|
209
|
+
"설치된 python-hwpx는 HWP 5.0(.hwp) 문서를 열거나 저장하지 못합니다.",
|
|
167
210
|
)
|
|
168
211
|
try:
|
|
169
212
|
document, resolved = self.storage.open_document(path)
|
|
@@ -186,6 +229,9 @@ class DocumentContext:
|
|
|
186
229
|
details={"requestedName": Path(path).name},
|
|
187
230
|
) from exc
|
|
188
231
|
except Exception as exc: # pragma: no cover - delegated to backend
|
|
232
|
+
hwp_error = self._hwp_error(exc)
|
|
233
|
+
if hwp_error is not None:
|
|
234
|
+
raise hwp_error from exc
|
|
189
235
|
raise self._new_error(
|
|
190
236
|
"DOCUMENT_OPEN_FAILED",
|
|
191
237
|
f"failed to open '{path}': {exc}",
|
|
@@ -299,6 +299,7 @@ class FormFieldService:
|
|
|
299
299
|
) from exc
|
|
300
300
|
|
|
301
301
|
source_path = self._context._resolve_path(path)
|
|
302
|
+
self._context._require_hwpx_package(source_path, output)
|
|
302
303
|
output_precondition = None
|
|
303
304
|
if isinstance(self._context.storage, LocalDocumentStorage):
|
|
304
305
|
output_precondition = (
|
|
@@ -468,6 +469,7 @@ class FormFieldService:
|
|
|
468
469
|
"installed python-hwpx does not provide hwpx.body_patch.apply_body_ops",
|
|
469
470
|
) from exc
|
|
470
471
|
source_path = self._context._resolve_path(path)
|
|
472
|
+
self._context._require_hwpx_package(source_path, output)
|
|
471
473
|
output_precondition = None
|
|
472
474
|
if isinstance(self._context.storage, LocalDocumentStorage):
|
|
473
475
|
output_precondition = (
|
|
@@ -633,6 +635,7 @@ class FormFieldService:
|
|
|
633
635
|
) from exc
|
|
634
636
|
|
|
635
637
|
blank = self._context._resolve_path(path)
|
|
638
|
+
self._context._require_hwpx_package(blank, output)
|
|
636
639
|
md = self._context._resolve_path(review_md)
|
|
637
640
|
output_precondition = None
|
|
638
641
|
if isinstance(self._context.storage, LocalDocumentStorage):
|
|
@@ -135,7 +135,7 @@ class PackageValidationService:
|
|
|
135
135
|
resolved = self._context._resolve_path(path)
|
|
136
136
|
patterns = [re.compile(pat) for pat in (forbid_patterns or [])]
|
|
137
137
|
warnings: List[Dict[str, Any]] = []
|
|
138
|
-
with create_text_extractor(resolved) as extractor:
|
|
138
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
139
139
|
for paragraph in extractor.iter_document_paragraphs():
|
|
140
140
|
text = paragraph.text()
|
|
141
141
|
if max_line_len is not None and len(text) > max_line_len:
|
|
@@ -39,7 +39,7 @@ class PlanningService:
|
|
|
39
39
|
def _ensure_planner_document(self, doc_id: str, path: str) -> None:
|
|
40
40
|
resolved = self._context._resolve_path(path)
|
|
41
41
|
paragraphs: List[str] = []
|
|
42
|
-
with create_text_extractor(resolved) as extractor:
|
|
42
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
43
43
|
for paragraph in extractor.iter_document_paragraphs():
|
|
44
44
|
paragraphs.append(paragraph.text(preserve_breaks=True))
|
|
45
45
|
self._manager.register_document(doc_id, "\n".join(paragraphs))
|
|
@@ -18,6 +18,7 @@ from ..upstream import (
|
|
|
18
18
|
AnnotationOptions,
|
|
19
19
|
create_object_finder,
|
|
20
20
|
create_text_extractor,
|
|
21
|
+
hwp5_conversion_report,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
from .context import DocumentContext
|
|
@@ -45,7 +46,7 @@ class ReadQueryService:
|
|
|
45
46
|
def get_paragraphs_by_handle(self, handle_id: str) -> Dict[str, Any]:
|
|
46
47
|
handle = self._context.get_registered_handle(handle_id)
|
|
47
48
|
resolved = self._context._resolve_path(handle.path)
|
|
48
|
-
if
|
|
49
|
+
if self._context._is_legacy_hwp(resolved):
|
|
49
50
|
paragraphs, _, _ = self._context._read_only_hwp_paragraphs(handle.path)
|
|
50
51
|
hwp_serialized = [
|
|
51
52
|
ParagraphResourceEntry(paragraphIndex=index, text=text)
|
|
@@ -57,7 +58,7 @@ class ReadQueryService:
|
|
|
57
58
|
return model.model_dump(by_alias=True)
|
|
58
59
|
|
|
59
60
|
serialized: List[ParagraphResourceEntry] = []
|
|
60
|
-
with create_text_extractor(resolved) as extractor:
|
|
61
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
61
62
|
for paragraph in extractor.iter_document_paragraphs():
|
|
62
63
|
serialized.append(
|
|
63
64
|
ParagraphResourceEntry(
|
|
@@ -73,7 +74,7 @@ class ReadQueryService:
|
|
|
73
74
|
def get_tables_by_handle(self, handle_id: str) -> Dict[str, Any]:
|
|
74
75
|
handle = self._context.get_registered_handle(handle_id)
|
|
75
76
|
resolved = self._context._resolve_path(handle.path)
|
|
76
|
-
if
|
|
77
|
+
if self._context._is_legacy_hwp(resolved):
|
|
77
78
|
model = DocumentTablesResource(handleId=handle.handle_id, tables=[])
|
|
78
79
|
return model.model_dump(by_alias=True)
|
|
79
80
|
|
|
@@ -92,7 +93,7 @@ class ReadQueryService:
|
|
|
92
93
|
|
|
93
94
|
def open_info(self, path: str) -> Dict[str, Any]:
|
|
94
95
|
resolved = self._context._resolve_path(path)
|
|
95
|
-
if
|
|
96
|
+
if self._context._is_legacy_hwp(resolved):
|
|
96
97
|
paragraphs, _, source = self._context._read_only_hwp_paragraphs(path)
|
|
97
98
|
stat = resolved.stat()
|
|
98
99
|
meta = {
|
|
@@ -123,6 +124,10 @@ class ReadQueryService:
|
|
|
123
124
|
"size": stat.st_size,
|
|
124
125
|
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
|
|
125
126
|
}
|
|
127
|
+
conversion = hwp5_conversion_report(document)
|
|
128
|
+
if conversion is not None:
|
|
129
|
+
meta["format"] = "hwp"
|
|
130
|
+
meta["hwpConversion"] = conversion
|
|
126
131
|
return {
|
|
127
132
|
"meta": meta,
|
|
128
133
|
"sectionCount": section_count,
|
|
@@ -169,7 +174,7 @@ class ReadQueryService:
|
|
|
169
174
|
with_footnotes: bool = False,
|
|
170
175
|
) -> Dict[str, Any]:
|
|
171
176
|
resolved = self._context._resolve_path(path)
|
|
172
|
-
if
|
|
177
|
+
if self._context._is_legacy_hwp(resolved):
|
|
173
178
|
hwp_paragraphs, _, _ = self._context._read_only_hwp_paragraphs(path)
|
|
174
179
|
effective_limit = (
|
|
175
180
|
self._context.paging_limit if limit is None else max(1, limit)
|
|
@@ -195,7 +200,7 @@ class ReadQueryService:
|
|
|
195
200
|
paragraphs: List[str] = []
|
|
196
201
|
next_offset: Optional[int] = None
|
|
197
202
|
start = max(0, offset)
|
|
198
|
-
with create_text_extractor(resolved) as extractor:
|
|
203
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
199
204
|
paragraph_iter = extractor.iter_document_paragraphs()
|
|
200
205
|
sentinel = object()
|
|
201
206
|
|
|
@@ -239,7 +244,7 @@ class ReadQueryService:
|
|
|
239
244
|
unique_indexes.add(int(index))
|
|
240
245
|
|
|
241
246
|
resolved = self._context._resolve_path(path)
|
|
242
|
-
if
|
|
247
|
+
if self._context._is_legacy_hwp(resolved):
|
|
243
248
|
paragraphs, _, _ = self._context._read_only_hwp_paragraphs(path)
|
|
244
249
|
hwp_collected = {
|
|
245
250
|
idx: paragraphs[idx] for idx in unique_indexes if idx < len(paragraphs)
|
|
@@ -266,7 +271,7 @@ class ReadQueryService:
|
|
|
266
271
|
)
|
|
267
272
|
|
|
268
273
|
collected: Dict[int, str] = {}
|
|
269
|
-
with create_text_extractor(resolved) as extractor:
|
|
274
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
270
275
|
for paragraph in extractor.iter_document_paragraphs():
|
|
271
276
|
para_index = paragraph.index
|
|
272
277
|
if para_index in unique_indexes and para_index not in collected:
|
|
@@ -292,7 +297,7 @@ class ReadQueryService:
|
|
|
292
297
|
|
|
293
298
|
def text_extract_report(self, path: str, mode: str = "plain") -> Dict[str, Any]:
|
|
294
299
|
resolved = self._context._resolve_path(path)
|
|
295
|
-
if
|
|
300
|
+
if self._context._is_legacy_hwp(resolved):
|
|
296
301
|
paragraphs, _, source = self._context._read_only_hwp_paragraphs(path)
|
|
297
302
|
return {
|
|
298
303
|
"content": "\n".join(paragraphs)
|
|
@@ -307,7 +312,7 @@ class ReadQueryService:
|
|
|
307
312
|
endnote="inline",
|
|
308
313
|
control="placeholder",
|
|
309
314
|
)
|
|
310
|
-
with create_text_extractor(resolved) as extractor:
|
|
315
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
311
316
|
content = extractor.extract_text(
|
|
312
317
|
annotations=annotations,
|
|
313
318
|
include_nested=True,
|
|
@@ -322,11 +327,11 @@ class ReadQueryService:
|
|
|
322
327
|
lock_keywords: Optional[Sequence[str]] = None,
|
|
323
328
|
) -> Dict[str, Any]:
|
|
324
329
|
resolved = self._context._resolve_path(path)
|
|
325
|
-
if
|
|
330
|
+
if self._context._is_legacy_hwp(resolved):
|
|
326
331
|
paragraphs, _, source = self._context._read_only_hwp_paragraphs(path)
|
|
327
332
|
else:
|
|
328
333
|
paragraphs = []
|
|
329
|
-
with create_text_extractor(resolved) as extractor:
|
|
334
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
330
335
|
for paragraph in extractor.iter_document_paragraphs():
|
|
331
336
|
paragraphs.append(paragraph.text(preserve_breaks=True))
|
|
332
337
|
source = "hwpx.text_extractor"
|
|
@@ -474,7 +479,7 @@ class ReadQueryService:
|
|
|
474
479
|
return snippet
|
|
475
480
|
|
|
476
481
|
pattern = re.compile(query) if is_regex else None
|
|
477
|
-
if
|
|
482
|
+
if self._context._is_legacy_hwp(resolved):
|
|
478
483
|
paragraphs, _, _ = self._context._read_only_hwp_paragraphs(path)
|
|
479
484
|
for para_index, text in enumerate(paragraphs):
|
|
480
485
|
if is_regex:
|
|
@@ -512,7 +517,7 @@ class ReadQueryService:
|
|
|
512
517
|
start = found + len(query)
|
|
513
518
|
return {"matches": matches}
|
|
514
519
|
|
|
515
|
-
with create_text_extractor(resolved) as extractor:
|
|
520
|
+
with create_text_extractor(self._context._text_source(resolved)) as extractor:
|
|
516
521
|
for paragraph in extractor.iter_document_paragraphs():
|
|
517
522
|
text = paragraph.text()
|
|
518
523
|
if is_regex:
|
|
@@ -558,7 +563,7 @@ class ReadQueryService:
|
|
|
558
563
|
max_results: int = 200,
|
|
559
564
|
) -> Dict[str, Any]:
|
|
560
565
|
resolved = self._context._resolve_path(path)
|
|
561
|
-
finder = create_object_finder(resolved)
|
|
566
|
+
finder = create_object_finder(self._context._text_source(resolved))
|
|
562
567
|
objects = []
|
|
563
568
|
for found in finder.iter(tag=tag_name, limit=max_results):
|
|
564
569
|
element = found.element
|
|
@@ -582,7 +587,7 @@ class ReadQueryService:
|
|
|
582
587
|
max_results: int = 200,
|
|
583
588
|
) -> Dict[str, Any]:
|
|
584
589
|
resolved = self._context._resolve_path(path)
|
|
585
|
-
finder = create_object_finder(resolved)
|
|
590
|
+
finder = create_object_finder(self._context._text_source(resolved))
|
|
586
591
|
tag_filter = None if element_type in {None, "", "*"} else element_type
|
|
587
592
|
attr_matcher: Any = value if value is not None else (lambda _: True)
|
|
588
593
|
objects = []
|