python-hwpx 2.29.2__py3-none-any.whl → 3.0.0__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.
hwpx/table_patch.py CHANGED
@@ -840,6 +840,25 @@ def _collapse_empty_rows(table: str) -> str:
840
840
  return _rebuild(prefix, rows, suffix, rowcnt=rowcnt)
841
841
 
842
842
 
843
+ def _physical_row_height(rows: Sequence[str], row: int) -> int | None:
844
+ """Return the exact height of a physical row when direct cells expose it.
845
+
846
+ A physical row can contain several ``rowSpan==1`` cells with different
847
+ ``cellSz`` heights. Hancom uses the tallest direct cell as the row height;
848
+ shorter values can belong to sparse/covered-looking cells. ``None`` means
849
+ the row is covered entirely by vertical merges and remains underivable.
850
+ """
851
+ heights: list[int] = []
852
+ for physical_row in rows:
853
+ for tc in _S_TC.findall(physical_row):
854
+ ra = _si(tc, "cellAddr", "rowAddr")
855
+ rs = _si(tc, "cellSpan", "rowSpan") or 1
856
+ height = _si(tc, "cellSz", "height")
857
+ if ra == row and rs == 1 and height is not None and height > 0:
858
+ heights.append(height)
859
+ return max(heights) if heights else None
860
+
861
+
843
862
  def _delete_rows(table: str, del_rows: Iterable[int]) -> str:
844
863
  """Delete physical rows by index, reconciling rowAddr/rowSpan and covering
845
864
  cells' height."""
@@ -849,6 +868,7 @@ def _delete_rows(table: str, del_rows: Iterable[int]) -> str:
849
868
  for empty in del_rows:
850
869
  if empty >= len(rows):
851
870
  raise TableStructureError(f"row index {empty} out of range")
871
+ exact_height = _physical_row_height(rows, empty)
852
872
  heights = []
853
873
  for r in rows:
854
874
  for tc in _S_TC.findall(r):
@@ -857,7 +877,9 @@ def _delete_rows(table: str, del_rows: Iterable[int]) -> str:
857
877
  h = _si(tc, "cellSz", "height")
858
878
  if h:
859
879
  heights.append(h // rs)
860
- drop_h = min(heights) if heights else 0
880
+ # Prefer the exact physical-row height. Fully merged rows expose no
881
+ # rowSpan==1 cell, so preserve the previous conservative estimate there.
882
+ drop_h = exact_height if exact_height is not None else (min(heights) if heights else 0)
861
883
 
862
884
  def fix(tc: str):
863
885
  ra, rs = _si(tc, "cellAddr", "rowAddr"), _si(tc, "cellSpan", "rowSpan") or 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.29.2
3
+ Version: 3.0.0
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -10,7 +10,7 @@ hwpx/guidance_scan.py,sha256=lN7wMUz0BaAgHCXdfK1CPEEmIqaFCuwpyL6XAQH6mqE,22921
10
10
  hwpx/package.py,sha256=0rKjGCJbPQvrVBIy07Jpjsu3fI7HhbqFCGWTiTDsJpo,1141
11
11
  hwpx/patch.py,sha256=8G1wgGVgCp0KyhQb-y0ZI2FJEatCwLt_JpepHJmYhYQ,23799
12
12
  hwpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- hwpx/table_patch.py,sha256=FCpCNQSX9jta12gmmSyDshB-okANYSL3O5YS0Rr1mX4,72358
13
+ hwpx/table_patch.py,sha256=lAHhtWiwIbJPJ6Jr68OgLnnxfUQevrfC7KIXqZHn5UU,73506
14
14
  hwpx/template_formfit.py,sha256=dlxf98FatT5Nl4hN15TuMXqj5NlDTGSnLaqXVo_PoBo,23424
15
15
  hwpx/templates.py,sha256=28bYqeJVeDb1Cq8G9NZG9Mhnu4K2GamAKC4QhxvUZyA,1187
16
16
  hwpx/agent/__init__.py,sha256=2pjX3M6SM3XnS6IsYjc64Jrm3YdbzsZPjbx7hBHMEl0,2665
@@ -119,21 +119,6 @@ hwpx/oxml/section.py,sha256=CRb4rlPPAifaOfHGZZUrdJJ8yZisUuuOqqd-FHmO0vk,359
119
119
  hwpx/oxml/simple_parts.py,sha256=wZ7HfmfpiSpCgZ-H5fMOS4xFq47jgpE3ssZm24pMvbQ,264
120
120
  hwpx/oxml/table.py,sha256=UaPS_HpFj91OQ5GQ5_DO8IzHe6fCx5mEwqElDkstYdI,363
121
121
  hwpx/oxml/utils.py,sha256=2L9au3SD_MFkFt2DXx3udXBT5caYuYO623lhGhgldVo,2972
122
- hwpx/practice/__init__.py,sha256=d0sAHfEeGJYo7V5whc_KOSzLqDZIsxuX-l60eDTun5g,8473
123
- hwpx/practice/aggregate.py,sha256=1VuK4qs3Pof2vCtNZlS1R9vEPMx-SKZ86dOwl74Bpd4,37441
124
- hwpx/practice/campaign.py,sha256=Gdy5Y7WJxNsE-bMRh4HaAcZg8xw6veCDu1kbHkI282E,11126
125
- hwpx/practice/domain.py,sha256=sGCof2R-i-0KNpwirzzCfGrV1T2zQs5m1biUKypFJ2g,122700
126
- hwpx/practice/dossier.py,sha256=NpVKttRlaSilYD2JejK4i8ZrXfEV1ISPX3Qf2oU49pI,3175
127
- hwpx/practice/evaluator.py,sha256=fACv3eBq4XMyXqOq0COcbz2Hr_oaK71bS4i6CaOzLTM,90618
128
- hwpx/practice/forge.py,sha256=z-P53JAo8Ie_TXDKx-slkP_1AAjG0-8_yENi9aa4SNc,19683
129
- hwpx/practice/intake.py,sha256=L7kVGPM3QRhPKfQNXlR1upCg_pm_telEPvp4jkfimMA,8383
130
- hwpx/practice/lineage.py,sha256=lw4w2gPX42OZ0O2CG2DZI6vWivNretLHIoRQoIIB2x0,4003
131
- hwpx/practice/mutations.py,sha256=5B2fG6Q5inObUYpoa_EWU937FqTthD0P_LzrJLQSX8I,6901
132
- hwpx/practice/registry.py,sha256=ZCIo7lazoaiXFaKjUPHogc7N0C2u7EA_UnJJF91E2dc,12990
133
- hwpx/practice/run.py,sha256=kfj5vGsQsfRdzqBpjWi0IEbSbpGGQv44N87HqhG967Y,29681
134
- hwpx/practice/sanitize.py,sha256=F2eVfK5HVSAKN3IE7VdpmlU_TeQ1MCEL8Ab1sci43ik,5827
135
- hwpx/practice/scenario.py,sha256=Wc7ctGiBVDRgVWlcNGT7v6pXI-aLfOPfarOO3c7ku6g,6434
136
- hwpx/practice/split.py,sha256=D43WH2n9lRofBRJTK6kG2BfHAzrKMwvnakkVzsgbhfU,9650
137
122
  hwpx/presets/__init__.py,sha256=I3gSJDT2tuvxXbw3FOmI3CnbxvjDMPZfppyg6OlMHOI,535
138
123
  hwpx/presets/proposal.py,sha256=2yzLfDxOAT0P19dPX1RBWh56_AIOMsWqINDadtnKQoc,21176
139
124
  hwpx/quality/__init__.py,sha256=zvOvfOYh0nlKH5ywpj9ZQHov0sdRIouicv9DamKmHLU,1478
@@ -199,10 +184,10 @@ hwpx/visual/page_qa.py,sha256=AuJCySfLIdXjPeekhAc3YnrIWOsN0sI35Pnz8BZ6Pro,7278
199
184
  hwpx/visual/qa_contracts.py,sha256=1cjoiRTAWgi7NgE8SPc6bKxdoUfKx9nyou1mgC47TxY,10506
200
185
  hwpx/visual/qa_metrics.py,sha256=I7RdybN-f1Fvcv2j-ceDPoek51nOkMui1Zrd7TEX_C8,9838
201
186
  hwpx/visual/report.py,sha256=2RhXN1KBYOZTim9FNpeUhaaDHR7oFxI6Z2DLUkDIiwE,1717
202
- python_hwpx-2.29.2.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
203
- python_hwpx-2.29.2.dist-info/licenses/NOTICE,sha256=k48h6EaGQE8Y1c0dS9sIOOcz4YqkbcImWClF7pBOgsg,2473
204
- python_hwpx-2.29.2.dist-info/METADATA,sha256=aCa8mBynKB05WHrwAvJPi8ou2Kn0O81VbwtJ3AQi41w,11525
205
- python_hwpx-2.29.2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
206
- python_hwpx-2.29.2.dist-info/entry_points.txt,sha256=PVUBTBQtBHiflQ9XBjfd004w-LrDibgZjwzxgu8Tx7w,480
207
- python_hwpx-2.29.2.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
208
- python_hwpx-2.29.2.dist-info/RECORD,,
187
+ python_hwpx-3.0.0.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
188
+ python_hwpx-3.0.0.dist-info/licenses/NOTICE,sha256=k48h6EaGQE8Y1c0dS9sIOOcz4YqkbcImWClF7pBOgsg,2473
189
+ python_hwpx-3.0.0.dist-info/METADATA,sha256=PXiYH9Ww3e5uadTiTp_UN0xb6QR4L9CzBzmtYNy878U,11524
190
+ python_hwpx-3.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
191
+ python_hwpx-3.0.0.dist-info/entry_points.txt,sha256=PVUBTBQtBHiflQ9XBjfd004w-LrDibgZjwzxgu8Tx7w,480
192
+ python_hwpx-3.0.0.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
193
+ python_hwpx-3.0.0.dist-info/RECORD,,
hwpx/practice/__init__.py DELETED
@@ -1,277 +0,0 @@
1
- """Privacy-gated contracts for deterministic HWPX practice corpora.
2
-
3
- The package deliberately starts with contracts and fail-closed validators. Real
4
- corpus intake and document mutation are added only after these boundaries are
5
- covered by tests.
6
- """
7
-
8
- from .lineage import (
9
- LINEAGE_KINDS,
10
- LineageEdge,
11
- build_lineage_groups,
12
- validate_partition_closure,
13
- )
14
- from .intake import (
15
- IntakeResult,
16
- ReviewDecision,
17
- apply_review_decision,
18
- intake_discovery_rows,
19
- )
20
- from .dossier import (
21
- SYNTHETIC_DOSSIER_SCHEMA,
22
- synthetic_dossier,
23
- validate_synthetic_dossier,
24
- )
25
- from .campaign import (
26
- ACTIVE_CAMPAIGN_STATES,
27
- CAMPAIGN_BUDGET_FIELDS,
28
- CAMPAIGN_STATES,
29
- PRACTICE_CAMPAIGN_MANIFEST_SCHEMA,
30
- TERMINAL_CAMPAIGN_STATES,
31
- build_campaign_manifest,
32
- campaign_manifest_sha256,
33
- validate_campaign_manifest,
34
- )
35
- from .aggregate import (
36
- PRACTICE_CAMPAIGN_AGGREGATE_SCHEMA,
37
- build_campaign_aggregate,
38
- campaign_aggregate_sha256,
39
- validate_campaign_aggregate,
40
- )
41
- from .domain import (
42
- ABSTENTION_INVENTORY_AUTH_SCHEMA,
43
- DOMAIN_EVALUATION_BUNDLE_SCHEMA,
44
- DOMAIN_REQUIREMENT_SCHEMA,
45
- DOMAIN_SOURCE_EVIDENCE_SCHEMA,
46
- DOMAIN_TERMINAL_SOURCE_EVIDENCE_SCHEMA,
47
- abstention_inventory_authentication_key_id,
48
- authoring_verifier_policy_sha256,
49
- build_authoring_domain_evidence,
50
- build_domain_evaluation_bundle,
51
- build_domain_requirement,
52
- build_edit_domain_evidence_from_semantic,
53
- build_exam_domain_evidence,
54
- build_exam_oracle_receipt,
55
- build_form_differential_receipt,
56
- build_form_target_policy,
57
- build_form_fill_domain_evidence_from_artifacts,
58
- build_must_abstain_domain_evidence_from_receipt,
59
- build_official_document_domain_evidence,
60
- build_structural_table_domain_evidence_from_artifacts,
61
- domain_requirement_policy_projection,
62
- domain_row_sha256,
63
- domain_value_sha256,
64
- exam_oracle_authentication_key_id,
65
- exam_verifier_policy_sha256,
66
- form_differential_oracle_provenance_sha256,
67
- form_differential_receipt_sha256,
68
- form_target_policy_sha256,
69
- form_verifier_policy_sha256,
70
- must_abstain_verifier_policy_sha256,
71
- official_verifier_policy_sha256,
72
- structural_verifier_policy_sha256,
73
- serialize_form_differential_receipt,
74
- validate_domain_evaluation_bundle,
75
- validate_domain_requirement,
76
- validate_exam_oracle_receipt,
77
- validate_form_differential_receipt,
78
- validate_form_target_policy,
79
- )
80
- from .evaluator import (
81
- EVALUATOR_RESULT_SCHEMA,
82
- EVALUATION_POLICY_SCHEMA,
83
- PACKAGE_POLICY_SCHEMA,
84
- SEMANTIC_POLICY_SCHEMA,
85
- build_idempotency_replay_receipt,
86
- build_package_policy,
87
- build_workflow_revision_receipt,
88
- combine_evaluation_result,
89
- current_evaluator_code_sha256,
90
- domain_layer_from_bundle,
91
- evaluate_package_layer,
92
- evaluate_semantic_layer,
93
- evaluation_policy_sha256,
94
- evaluator_authentication_key_id,
95
- semantic_policy_projection,
96
- validate_evaluation_result,
97
- )
98
- from .forge import (
99
- EVALUATOR_MANIFEST_SCHEMA,
100
- RUNNER_MANIFEST_SCHEMA,
101
- SCENARIO_PACK_SCHEMA,
102
- ForgeConfig,
103
- forge_scenario_pack,
104
- runner_view,
105
- validate_scenario_pack,
106
- write_scenario_pack,
107
- )
108
- from .mutations import (
109
- CONTROLLED_MUTATION_SCHEMA,
110
- apply_mutation,
111
- controlled_mutation,
112
- mutation_sha256,
113
- reverse_mutation,
114
- validate_controlled_mutation,
115
- )
116
- from .registry import (
117
- PRIVATE_REGISTRY_SCHEMA,
118
- REDACTED_REGISTRY_SCHEMA,
119
- SOURCE_INTEGRITY_SCHEMA,
120
- assert_redacted_payload,
121
- build_source_integrity_receipt,
122
- eligibility_status,
123
- opaque_document_id,
124
- redact_private_record,
125
- snapshot_source_tree,
126
- validate_private_record,
127
- validate_storage_roots,
128
- )
129
- from .scenario import PRACTICE_SCENARIO_SCHEMA, scenario_id, validate_scenario
130
- from .run import (
131
- ACTIVE_RUN_STATES,
132
- PRACTICE_RUN_EVENT_SCHEMA,
133
- PRACTICE_RUN_RECEIPT_SCHEMA,
134
- PRACTICE_RUN_SCHEMA,
135
- RUN_BUDGET_FIELDS,
136
- RUN_STATES,
137
- SCENARIO_EXPECTED_STATES,
138
- TERMINAL_RUN_STATES,
139
- assert_receipt_safe,
140
- practice_run_id,
141
- redact_run_receipt,
142
- validate_exact_provenance,
143
- validate_practice_run,
144
- validate_run_budgets,
145
- validate_run_receipt,
146
- workflow_event_id,
147
- )
148
- from .sanitize import DERIVATIVE_ID_PATTERN, sanitize_document_copy
149
- from .split import SPLIT_MANIFEST_SCHEMA, build_split_manifest, validate_split_manifest
150
-
151
- __all__ = [
152
- "ABSTENTION_INVENTORY_AUTH_SCHEMA",
153
- "ACTIVE_CAMPAIGN_STATES",
154
- "ACTIVE_RUN_STATES",
155
- "CAMPAIGN_BUDGET_FIELDS",
156
- "CAMPAIGN_STATES",
157
- "LINEAGE_KINDS",
158
- "CONTROLLED_MUTATION_SCHEMA",
159
- "EVALUATOR_MANIFEST_SCHEMA",
160
- "DERIVATIVE_ID_PATTERN",
161
- "DOMAIN_EVALUATION_BUNDLE_SCHEMA",
162
- "DOMAIN_REQUIREMENT_SCHEMA",
163
- "DOMAIN_SOURCE_EVIDENCE_SCHEMA",
164
- "DOMAIN_TERMINAL_SOURCE_EVIDENCE_SCHEMA",
165
- "EVALUATOR_RESULT_SCHEMA",
166
- "EVALUATION_POLICY_SCHEMA",
167
- "ForgeConfig",
168
- "PRIVATE_REGISTRY_SCHEMA",
169
- "PRACTICE_SCENARIO_SCHEMA",
170
- "PRACTICE_CAMPAIGN_MANIFEST_SCHEMA",
171
- "PRACTICE_CAMPAIGN_AGGREGATE_SCHEMA",
172
- "PRACTICE_RUN_EVENT_SCHEMA",
173
- "PRACTICE_RUN_RECEIPT_SCHEMA",
174
- "PRACTICE_RUN_SCHEMA",
175
- "REDACTED_REGISTRY_SCHEMA",
176
- "PACKAGE_POLICY_SCHEMA",
177
- "SOURCE_INTEGRITY_SCHEMA",
178
- "LineageEdge",
179
- "IntakeResult",
180
- "ReviewDecision",
181
- "RUNNER_MANIFEST_SCHEMA",
182
- "RUN_BUDGET_FIELDS",
183
- "RUN_STATES",
184
- "SCENARIO_EXPECTED_STATES",
185
- "SCENARIO_PACK_SCHEMA",
186
- "SEMANTIC_POLICY_SCHEMA",
187
- "SPLIT_MANIFEST_SCHEMA",
188
- "SYNTHETIC_DOSSIER_SCHEMA",
189
- "TERMINAL_CAMPAIGN_STATES",
190
- "TERMINAL_RUN_STATES",
191
- "apply_mutation",
192
- "abstention_inventory_authentication_key_id",
193
- "apply_review_decision",
194
- "authoring_verifier_policy_sha256",
195
- "assert_redacted_payload",
196
- "assert_receipt_safe",
197
- "build_lineage_groups",
198
- "build_split_manifest",
199
- "build_source_integrity_receipt",
200
- "build_campaign_manifest",
201
- "build_campaign_aggregate",
202
- "build_authoring_domain_evidence",
203
- "build_domain_evaluation_bundle",
204
- "build_domain_requirement",
205
- "build_edit_domain_evidence_from_semantic",
206
- "build_exam_domain_evidence",
207
- "build_exam_oracle_receipt",
208
- "build_form_differential_receipt",
209
- "build_form_target_policy",
210
- "build_form_fill_domain_evidence_from_artifacts",
211
- "build_must_abstain_domain_evidence_from_receipt",
212
- "build_official_document_domain_evidence",
213
- "build_package_policy",
214
- "build_idempotency_replay_receipt",
215
- "build_workflow_revision_receipt",
216
- "build_structural_table_domain_evidence_from_artifacts",
217
- "campaign_manifest_sha256",
218
- "campaign_aggregate_sha256",
219
- "combine_evaluation_result",
220
- "current_evaluator_code_sha256",
221
- "domain_layer_from_bundle",
222
- "domain_requirement_policy_projection",
223
- "domain_row_sha256",
224
- "domain_value_sha256",
225
- "exam_oracle_authentication_key_id",
226
- "exam_verifier_policy_sha256",
227
- "evaluate_package_layer",
228
- "evaluate_semantic_layer",
229
- "evaluation_policy_sha256",
230
- "evaluator_authentication_key_id",
231
- "eligibility_status",
232
- "controlled_mutation",
233
- "forge_scenario_pack",
234
- "form_target_policy_sha256",
235
- "form_differential_oracle_provenance_sha256",
236
- "form_differential_receipt_sha256",
237
- "form_verifier_policy_sha256",
238
- "must_abstain_verifier_policy_sha256",
239
- "opaque_document_id",
240
- "practice_run_id",
241
- "mutation_sha256",
242
- "official_verifier_policy_sha256",
243
- "intake_discovery_rows",
244
- "redact_private_record",
245
- "redact_run_receipt",
246
- "scenario_id",
247
- "sanitize_document_copy",
248
- "runner_view",
249
- "reverse_mutation",
250
- "snapshot_source_tree",
251
- "structural_verifier_policy_sha256",
252
- "serialize_form_differential_receipt",
253
- "validate_partition_closure",
254
- "validate_campaign_manifest",
255
- "validate_campaign_aggregate",
256
- "validate_domain_evaluation_bundle",
257
- "validate_domain_requirement",
258
- "validate_evaluation_result",
259
- "validate_exam_oracle_receipt",
260
- "validate_form_differential_receipt",
261
- "validate_form_target_policy",
262
- "validate_exact_provenance",
263
- "validate_practice_run",
264
- "validate_private_record",
265
- "validate_scenario",
266
- "validate_run_budgets",
267
- "validate_run_receipt",
268
- "synthetic_dossier",
269
- "validate_controlled_mutation",
270
- "validate_scenario_pack",
271
- "validate_synthetic_dossier",
272
- "validate_split_manifest",
273
- "validate_storage_roots",
274
- "semantic_policy_projection",
275
- "write_scenario_pack",
276
- "workflow_event_id",
277
- ]