python-hwpx-automation 6.0.3__py3-none-any.whl

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.
Files changed (217) hide show
  1. hwpx_automation/__init__.py +61 -0
  2. hwpx_automation/__init__.pyi +27 -0
  3. hwpx_automation/__main__.py +8 -0
  4. hwpx_automation/agent_document.py +392 -0
  5. hwpx_automation/api.py +136 -0
  6. hwpx_automation/blind_eval.py +407 -0
  7. hwpx_automation/capabilities.py +110 -0
  8. hwpx_automation/compat.py +48 -0
  9. hwpx_automation/configuration.py +60 -0
  10. hwpx_automation/core/__init__.py +2 -0
  11. hwpx_automation/core/content.py +762 -0
  12. hwpx_automation/core/context.py +111 -0
  13. hwpx_automation/core/diff.py +53 -0
  14. hwpx_automation/core/document.py +37 -0
  15. hwpx_automation/core/formatting.py +513 -0
  16. hwpx_automation/core/handles.py +24 -0
  17. hwpx_automation/core/locations.py +205 -0
  18. hwpx_automation/core/locator.py +162 -0
  19. hwpx_automation/core/plan.py +680 -0
  20. hwpx_automation/core/resources.py +42 -0
  21. hwpx_automation/core/search.py +296 -0
  22. hwpx_automation/core/transactions.py +434 -0
  23. hwpx_automation/core/txn.py +48 -0
  24. hwpx_automation/document_state.py +95 -0
  25. hwpx_automation/errors.py +174 -0
  26. hwpx_automation/execution_lock.py +15 -0
  27. hwpx_automation/fastmcp_adapter.py +672 -0
  28. hwpx_automation/form_fill.py +1177 -0
  29. hwpx_automation/form_output_models.py +223 -0
  30. hwpx_automation/handlers/__init__.py +2 -0
  31. hwpx_automation/handlers/_shared.py +377 -0
  32. hwpx_automation/handlers/agent_document.py +257 -0
  33. hwpx_automation/handlers/authoring.py +750 -0
  34. hwpx_automation/handlers/content_edit.py +1078 -0
  35. hwpx_automation/handlers/form_fill.py +607 -0
  36. hwpx_automation/handlers/layout_style.py +660 -0
  37. hwpx_automation/handlers/quality_render.py +566 -0
  38. hwpx_automation/handlers/read_export.py +1295 -0
  39. hwpx_automation/handlers/specialized.py +624 -0
  40. hwpx_automation/handlers/tracked_changes.py +589 -0
  41. hwpx_automation/handlers/workflow.py +105 -0
  42. hwpx_automation/hwp_converter.py +227 -0
  43. hwpx_automation/hwp_support.py +94 -0
  44. hwpx_automation/hwpx_ops.py +1439 -0
  45. hwpx_automation/identity.json +263 -0
  46. hwpx_automation/identity.py +18 -0
  47. hwpx_automation/ingest_adapters.py +85 -0
  48. hwpx_automation/markdown_plan.py +216 -0
  49. hwpx_automation/mcp_cli.py +29 -0
  50. hwpx_automation/metadata/tools_meta.py +40 -0
  51. hwpx_automation/mixed_form.py +3007 -0
  52. hwpx_automation/mutation_models.py +401 -0
  53. hwpx_automation/network_policy.py +232 -0
  54. hwpx_automation/office/__init__.py +14 -0
  55. hwpx_automation/office/agent/__init__.py +125 -0
  56. hwpx_automation/office/agent/_batch_verification.py +383 -0
  57. hwpx_automation/office/agent/blueprint/__init__.py +58 -0
  58. hwpx_automation/office/agent/blueprint/bundle.py +282 -0
  59. hwpx_automation/office/agent/blueprint/catalog.py +136 -0
  60. hwpx_automation/office/agent/blueprint/dump.py +520 -0
  61. hwpx_automation/office/agent/blueprint/mapping.py +312 -0
  62. hwpx_automation/office/agent/blueprint/model.py +722 -0
  63. hwpx_automation/office/agent/blueprint/native.py +621 -0
  64. hwpx_automation/office/agent/blueprint/replay.py +622 -0
  65. hwpx_automation/office/agent/catalog.py +252 -0
  66. hwpx_automation/office/agent/cli.py +647 -0
  67. hwpx_automation/office/agent/commands.py +1383 -0
  68. hwpx_automation/office/agent/document.py +801 -0
  69. hwpx_automation/office/agent/form_plan.py +1760 -0
  70. hwpx_automation/office/agent/model.py +808 -0
  71. hwpx_automation/office/agent/path.py +155 -0
  72. hwpx_automation/office/agent/query.py +230 -0
  73. hwpx_automation/office/agent/story.py +207 -0
  74. hwpx_automation/office/authoring/__init__.py +3542 -0
  75. hwpx_automation/office/authoring/advanced_generators.py +154 -0
  76. hwpx_automation/office/authoring/builder/__init__.py +52 -0
  77. hwpx_automation/office/authoring/builder/core.py +996 -0
  78. hwpx_automation/office/authoring/builder/report.py +195 -0
  79. hwpx_automation/office/authoring/design/__init__.py +30 -0
  80. hwpx_automation/office/authoring/design/_support.py +144 -0
  81. hwpx_automation/office/authoring/design/composer.py +282 -0
  82. hwpx_automation/office/authoring/design/harvest.py +305 -0
  83. hwpx_automation/office/authoring/design/plan.py +69 -0
  84. hwpx_automation/office/authoring/design/profile.py +88 -0
  85. hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +1 -0
  86. hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +1 -0
  87. hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +1 -0
  88. hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +1 -0
  89. hwpx_automation/office/authoring/design/profiles/application_form/profile.json +25 -0
  90. hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
  91. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +1 -0
  92. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +1 -0
  93. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +1 -0
  94. hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +24 -0
  95. hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
  96. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +1 -0
  97. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +1 -0
  98. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +1 -0
  99. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +1 -0
  100. hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +25 -0
  101. hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
  102. hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +1 -0
  103. hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +1 -0
  104. hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +1 -0
  105. hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +1 -0
  106. hwpx_automation/office/authoring/design/profiles/report/profile.json +25 -0
  107. hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
  108. hwpx_automation/office/authoring/design/validator.py +107 -0
  109. hwpx_automation/office/authoring/presets/__init__.py +22 -0
  110. hwpx_automation/office/authoring/presets/proposal.py +538 -0
  111. hwpx_automation/office/authoring/report_parser.py +141 -0
  112. hwpx_automation/office/authoring/style_profile.py +437 -0
  113. hwpx_automation/office/authoring/template_analyzer.py +657 -0
  114. hwpx_automation/office/compliance/__init__.py +38 -0
  115. hwpx_automation/office/compliance/official_lint.py +478 -0
  116. hwpx_automation/office/compliance/pii.py +388 -0
  117. hwpx_automation/office/document_ops/__init__.py +13 -0
  118. hwpx_automation/office/document_ops/comparison.py +62 -0
  119. hwpx_automation/office/document_ops/mail_merge.py +73 -0
  120. hwpx_automation/office/document_ops/redline.py +35 -0
  121. hwpx_automation/office/evalplan/__init__.py +36 -0
  122. hwpx_automation/office/evalplan/runtime.py +2762 -0
  123. hwpx_automation/office/exam/__init__.py +44 -0
  124. hwpx_automation/office/exam/compose.py +282 -0
  125. hwpx_automation/office/exam/ir.py +44 -0
  126. hwpx_automation/office/exam/measure.py +163 -0
  127. hwpx_automation/office/exam/parser.py +150 -0
  128. hwpx_automation/office/exam/profile.py +123 -0
  129. hwpx_automation/office/form_fill/__init__.py +66 -0
  130. hwpx_automation/office/form_fill/classification.py +108 -0
  131. hwpx_automation/office/form_fill/fill_residue.py +242 -0
  132. hwpx_automation/office/form_fill/fit/__init__.py +36 -0
  133. hwpx_automation/office/form_fill/fit/apply.py +24 -0
  134. hwpx_automation/office/form_fill/fit/engine.py +24 -0
  135. hwpx_automation/office/form_fill/fit/measure.py +50 -0
  136. hwpx_automation/office/form_fill/fit/policy.py +28 -0
  137. hwpx_automation/office/form_fill/fit/report.py +28 -0
  138. hwpx_automation/office/form_fill/fit/seal.py +457 -0
  139. hwpx_automation/office/form_fill/fit/wordbox.py +1343 -0
  140. hwpx_automation/office/form_fill/guidance.py +704 -0
  141. hwpx_automation/office/form_fill/quality.py +961 -0
  142. hwpx_automation/office/form_fill/split_run.py +333 -0
  143. hwpx_automation/office/form_fill/template_formfit.py +656 -0
  144. hwpx_automation/office/house_style/__init__.py +196 -0
  145. hwpx_automation/office/house_style/composition.py +68 -0
  146. hwpx_automation/office/house_style/data/bank.json +625 -0
  147. hwpx_automation/office/house_style/data/genres.json +43 -0
  148. hwpx_automation/office/quality/__init__.py +14 -0
  149. hwpx_automation/office/quality/page_guard.py +277 -0
  150. hwpx_automation/office/rendering/__init__.py +145 -0
  151. hwpx_automation/office/rendering/_hancom_open_rate.ps1 +374 -0
  152. hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +162 -0
  153. hwpx_automation/office/rendering/_render_hwpx.ps1 +72 -0
  154. hwpx_automation/office/rendering/_render_hwpx_mac.applescript +249 -0
  155. hwpx_automation/office/rendering/block_splits.py +76 -0
  156. hwpx_automation/office/rendering/detectors.py +151 -0
  157. hwpx_automation/office/rendering/diff.py +153 -0
  158. hwpx_automation/office/rendering/fixture_corpus.py +215 -0
  159. hwpx_automation/office/rendering/oracle.py +909 -0
  160. hwpx_automation/office/rendering/page_qa.py +245 -0
  161. hwpx_automation/office/rendering/qa_contracts.py +293 -0
  162. hwpx_automation/office/rendering/qa_metrics.py +241 -0
  163. hwpx_automation/office/rendering/worker.py +290 -0
  164. hwpx_automation/office/utilities/__init__.py +12 -0
  165. hwpx_automation/office/utilities/table_compute.py +477 -0
  166. hwpx_automation/ops_services/__init__.py +1 -0
  167. hwpx_automation/ops_services/_border_fill.py +283 -0
  168. hwpx_automation/ops_services/composition.py +55 -0
  169. hwpx_automation/ops_services/content_layout.py +322 -0
  170. hwpx_automation/ops_services/context.py +213 -0
  171. hwpx_automation/ops_services/form_fields.py +557 -0
  172. hwpx_automation/ops_services/media.py +178 -0
  173. hwpx_automation/ops_services/memo_style.py +477 -0
  174. hwpx_automation/ops_services/package_validation.py +166 -0
  175. hwpx_automation/ops_services/planning.py +201 -0
  176. hwpx_automation/ops_services/preview_export.py +585 -0
  177. hwpx_automation/ops_services/read_query.py +601 -0
  178. hwpx_automation/ops_services/save_policy.py +604 -0
  179. hwpx_automation/ops_services/tables.py +539 -0
  180. hwpx_automation/ops_services/transactions.py +616 -0
  181. hwpx_automation/preview_output_models.py +69 -0
  182. hwpx_automation/public-modules.json +206 -0
  183. hwpx_automation/py.typed +1 -0
  184. hwpx_automation/quality.py +351 -0
  185. hwpx_automation/quality_generation.py +725 -0
  186. hwpx_automation/runtime.py +321 -0
  187. hwpx_automation/runtime_services.py +100 -0
  188. hwpx_automation/server.py +259 -0
  189. hwpx_automation/storage.py +747 -0
  190. hwpx_automation/tool_bindings.py +170 -0
  191. hwpx_automation/tool_contract.py +982 -0
  192. hwpx_automation/upstream.py +755 -0
  193. hwpx_automation/utils/__init__.py +2 -0
  194. hwpx_automation/utils/helpers.py +29 -0
  195. hwpx_automation/visual_qa.py +667 -0
  196. hwpx_automation/workflow/__init__.py +55 -0
  197. hwpx_automation/workflow/adapters.py +482 -0
  198. hwpx_automation/workflow/dispatcher.py +213 -0
  199. hwpx_automation/workflow/models.py +243 -0
  200. hwpx_automation/workflow/policy.py +198 -0
  201. hwpx_automation/workflow/render_contracts.py +173 -0
  202. hwpx_automation/workflow/render_metrics.py +196 -0
  203. hwpx_automation/workflow/render_queue.py +482 -0
  204. hwpx_automation/workflow/render_security.py +172 -0
  205. hwpx_automation/workflow/render_transport.py +369 -0
  206. hwpx_automation/workflow/rendering.py +206 -0
  207. hwpx_automation/workflow/service.py +758 -0
  208. hwpx_automation/workflow/state_machine.py +65 -0
  209. hwpx_automation/workflow/store.py +747 -0
  210. hwpx_automation/workspace.py +1694 -0
  211. python_hwpx_automation-6.0.3.dist-info/METADATA +279 -0
  212. python_hwpx_automation-6.0.3.dist-info/RECORD +217 -0
  213. python_hwpx_automation-6.0.3.dist-info/WHEEL +5 -0
  214. python_hwpx_automation-6.0.3.dist-info/entry_points.txt +3 -0
  215. python_hwpx_automation-6.0.3.dist-info/licenses/LICENSE +178 -0
  216. python_hwpx_automation-6.0.3.dist-info/licenses/NOTICE +14 -0
  217. python_hwpx_automation-6.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,213 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import logging
7
+ from pathlib import Path
8
+ from typing import Any, Callable, Dict, List, Optional, Tuple
9
+
10
+ from ..hwp_support import HwpBinaryError, extract_hwp_text
11
+ from ..core.locator import RegisteredHandle
12
+ from ..core.context import default_session_lifecycle_policy
13
+ from ..storage import DocumentStorage, LocalDocumentStorage
14
+ from ..workspace import (
15
+ WorkspacePathError,
16
+ )
17
+ from ..upstream import (
18
+ HwpxDocument,
19
+ HwpxOxmlParagraph,
20
+ HwpxOxmlTable,
21
+ )
22
+
23
+ logger = logging.getLogger("hwpx_automation.hwpx_ops")
24
+
25
+
26
+ class DocumentContext:
27
+ def __init__(
28
+ self,
29
+ *,
30
+ storage: DocumentStorage,
31
+ paging_paragraph_limit: int,
32
+ error_type: Callable[..., RuntimeError],
33
+ handle_error_type: type[RuntimeError],
34
+ ) -> None:
35
+ self.storage = storage
36
+ self.base_directory = storage.base_directory
37
+ self.paging_limit = max(1, paging_paragraph_limit)
38
+ self._registered_handles: Dict[str, RegisteredHandle] = {}
39
+ self._error_type = error_type
40
+ self._handle_error_type = handle_error_type
41
+
42
+ @property
43
+ def registered_handles(self) -> Dict[str, RegisteredHandle]:
44
+ return self._registered_handles
45
+
46
+ def _local_storage(self) -> LocalDocumentStorage:
47
+ """Return :attr:`storage` narrowed to the local filesystem backend.
48
+
49
+ Guarded exact-sidecar publication (``atomic_publish_bytes`` /
50
+ ``read_guarded_bytes`` / ``remove_guarded_output`` /
51
+ ``materialize_output_guard`` / ``cleanup_owned_parent_directories``) is a
52
+ filesystem-workspace capability only :class:`LocalDocumentStorage`
53
+ provides; non-local backends route through their own fallback paths.
54
+ Every caller reaches these methods only after an ``isinstance`` gate or
55
+ ``_capture_exact_sidecar_guard`` has already established the local
56
+ backend, so this re-expresses that invariant for the type checker and
57
+ fails closed with the same error the sidecar machinery already raises.
58
+ """
59
+ storage = self.storage
60
+ if not isinstance(storage, LocalDocumentStorage):
61
+ raise TypeError("exact sidecar operations require local storage")
62
+ return storage
63
+
64
+ def _new_error(
65
+ self,
66
+ code: str,
67
+ message: str,
68
+ *,
69
+ details: Optional[Dict[str, Any]] = None,
70
+ hint: Optional[str] = None,
71
+ ) -> RuntimeError:
72
+ return self._error_type(message, code=code, details=details, hint=hint)
73
+
74
+ def _resolve_path(self, path: str, *, must_exist: bool = True) -> Path:
75
+ try:
76
+ resolved = self.storage.resolve_path(path, must_exist=must_exist)
77
+ except FileNotFoundError as exc:
78
+ raise self._new_error(
79
+ "DOCUMENT_NOT_FOUND",
80
+ "요청한 문서를 허용된 작업공간에서 찾을 수 없습니다.",
81
+ details={"requestedName": Path(path).name},
82
+ ) from exc
83
+ except WorkspacePathError as exc:
84
+ raise self._new_error(
85
+ exc.code,
86
+ "요청한 경로가 허용된 HWPX 작업공간 경계를 벗어났습니다.",
87
+ details=exc.safe_details(),
88
+ ) from exc
89
+ except PermissionError as exc:
90
+ raise self._new_error(
91
+ "PERMISSION_DENIED",
92
+ "요청한 문서에 접근할 권한이 없습니다.",
93
+ details={"requestedName": Path(path).name},
94
+ ) from exc
95
+ self._register_handle(path, resolved)
96
+ return resolved
97
+
98
+ def _make_handle_id(self, path: str, backend: Optional[str] = None) -> str:
99
+ seed = f"{backend or 'local'}::{path}"
100
+ digest = hashlib.sha256(seed.encode("utf-8")).hexdigest()[:16]
101
+ return f"h_{digest}"
102
+
103
+ def _register_handle(self, path: str, resolved: Path) -> RegisteredHandle:
104
+ relative = self._relative_path(resolved)
105
+ handle_id = self._make_handle_id(relative)
106
+ handle = RegisteredHandle(type="handle", handleId=handle_id, path=relative)
107
+ self._registered_handles[handle_id] = handle
108
+ return handle
109
+
110
+ def list_registered_handles(self) -> List[RegisteredHandle]:
111
+ return sorted(
112
+ self._registered_handles.values(), key=lambda item: item.handle_id
113
+ )
114
+
115
+ def open_document_handle(self, path: str) -> Dict[str, Any]:
116
+ resolved = self._resolve_path(path)
117
+ handle = self._register_handle(path, resolved)
118
+ return {"handle": handle.model_dump(by_alias=True)}
119
+
120
+ def list_open_documents(self) -> Dict[str, Any]:
121
+ policy = default_session_lifecycle_policy()
122
+ return {
123
+ "documents": [
124
+ handle.model_dump(by_alias=True)
125
+ for handle in self.list_registered_handles()
126
+ ],
127
+ "sessionPolicy": policy.as_dict(),
128
+ }
129
+
130
+ def close_document_handle(self, handle_id: str) -> Dict[str, Any]:
131
+ removed = self._registered_handles.pop(handle_id, None)
132
+ return {"closed": removed is not None}
133
+
134
+ def get_registered_handle(self, handle_id: str) -> RegisteredHandle:
135
+ handle = self._registered_handles.get(handle_id)
136
+ if handle is None:
137
+ raise self._handle_error_type(f"등록되지 않은 handleId입니다: {handle_id}")
138
+ return handle
139
+
140
+ def resolve_document_path(
141
+ self,
142
+ *,
143
+ path: Optional[str] = None,
144
+ handle_id: Optional[str] = None,
145
+ ) -> str:
146
+ if path:
147
+ return path
148
+ if handle_id:
149
+ return self.get_registered_handle(handle_id).path
150
+ raise self._new_error(
151
+ "DOCUMENT_LOCATOR_REQUIRED",
152
+ "path 또는 handleId 중 하나를 제공해야 합니다.",
153
+ )
154
+
155
+ def _resolve_output_path(self, path: str) -> Path:
156
+ return self.storage.resolve_output_path(path)
157
+
158
+ def _relative_path(self, path: Path) -> str:
159
+ return self.storage.relative_path(path)
160
+
161
+ def _open_document(self, path: str) -> Tuple[HwpxDocument, Path]:
162
+ resolved = self._resolve_path(path)
163
+ if resolved.suffix.lower() == ".hwp":
164
+ raise self._new_error(
165
+ "READ_ONLY_HWP_DOCUMENT",
166
+ "HWP 파일은 편집이 불가합니다. 먼저 convert_hwp_to_hwpx 도구로 HWPX 변환 후 편집하세요.",
167
+ )
168
+ try:
169
+ document, resolved = self.storage.open_document(path)
170
+ except FileNotFoundError as exc:
171
+ raise self._new_error(
172
+ "DOCUMENT_NOT_FOUND",
173
+ "요청한 문서를 허용된 작업공간에서 찾을 수 없습니다.",
174
+ details={"requestedName": Path(path).name},
175
+ ) from exc
176
+ except WorkspacePathError as exc:
177
+ raise self._new_error(
178
+ exc.code,
179
+ "요청한 경로가 허용된 HWPX 작업공간 경계를 벗어났습니다.",
180
+ details=exc.safe_details(),
181
+ ) from exc
182
+ except PermissionError as exc:
183
+ raise self._new_error(
184
+ "PERMISSION_DENIED",
185
+ "요청한 문서에 접근할 권한이 없습니다.",
186
+ details={"requestedName": Path(path).name},
187
+ ) from exc
188
+ except Exception as exc: # pragma: no cover - delegated to backend
189
+ raise self._new_error(
190
+ "DOCUMENT_OPEN_FAILED",
191
+ f"failed to open '{path}': {exc}",
192
+ details={"path": path},
193
+ ) from exc
194
+ return document, resolved
195
+
196
+ def _read_only_hwp_paragraphs(self, path: str) -> Tuple[List[str], Path, str]:
197
+ resolved = self._resolve_path(path)
198
+ try:
199
+ snapshot = extract_hwp_text(resolved)
200
+ except HwpBinaryError as exc:
201
+ raise self._new_error(
202
+ "HWP_TEXT_EXTRACT_FAILED", f"HWP 텍스트 추출 실패: {exc}"
203
+ ) from exc
204
+ return snapshot.paragraphs, resolved, snapshot.source
205
+
206
+ def _iter_paragraphs(self, document: HwpxDocument) -> List[HwpxOxmlParagraph]:
207
+ return list(document.paragraphs)
208
+
209
+ def _iter_tables(self, document: HwpxDocument) -> List[HwpxOxmlTable]:
210
+ tables: List[HwpxOxmlTable] = []
211
+ for paragraph in document.paragraphs:
212
+ tables.extend(paragraph.tables)
213
+ return tables