python-hwpx 2.24.0__py3-none-any.whl → 2.24.1__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/oxml/_document_impl.py +11 -2
- hwpx/table_patch.py +30 -0
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/METADATA +11 -2
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/RECORD +9 -9
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/WHEEL +0 -0
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/entry_points.txt +0 -0
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/licenses/LICENSE +0 -0
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/licenses/NOTICE +0 -0
- {python_hwpx-2.24.0.dist-info → python_hwpx-2.24.1.dist-info}/top_level.txt +0 -0
hwpx/oxml/_document_impl.py
CHANGED
|
@@ -2796,14 +2796,23 @@ class HwpxOxmlTableCell:
|
|
|
2796
2796
|
preserve_format: bool = True,
|
|
2797
2797
|
split_paragraphs: bool = False,
|
|
2798
2798
|
) -> None:
|
|
2799
|
+
previous_text = self.text
|
|
2800
|
+
sanitized_value = _sanitize_text(value)
|
|
2801
|
+
if sanitized_value and sanitized_value != previous_text:
|
|
2802
|
+
sublist = self._ensure_sublist()
|
|
2803
|
+
if (sublist.get("lineWrap") or "").upper() == "SQUEEZE":
|
|
2804
|
+
# SQUEEZE can compress a longer filled value until Hancom
|
|
2805
|
+
# renders adjacent glyphs on top of each other. New content
|
|
2806
|
+
# should wrap/reflow; untouched template cells keep their mode.
|
|
2807
|
+
sublist.set("lineWrap", "BREAK")
|
|
2799
2808
|
if split_paragraphs:
|
|
2800
|
-
self._set_split_paragraph_text(
|
|
2809
|
+
self._set_split_paragraph_text(sanitized_value)
|
|
2801
2810
|
self.element.set("dirty", "1")
|
|
2802
2811
|
self.table.mark_dirty()
|
|
2803
2812
|
return
|
|
2804
2813
|
|
|
2805
2814
|
text_element = self._ensure_text_element()
|
|
2806
|
-
text_element.text =
|
|
2815
|
+
text_element.text = sanitized_value
|
|
2807
2816
|
for node in self.element.findall(f".//{_HP}t"):
|
|
2808
2817
|
if node is text_element:
|
|
2809
2818
|
continue
|
hwpx/table_patch.py
CHANGED
|
@@ -182,6 +182,9 @@ def build_grid(table: bytes) -> tuple[dict[tuple[int, int], _Cell], GridReport]:
|
|
|
182
182
|
|
|
183
183
|
|
|
184
184
|
_P_SPAN_RE = re.compile(rb"<(?:[A-Za-z_][\w.-]*:)?p\b.*?</(?:[A-Za-z_][\w.-]*:)?p>", re.DOTALL)
|
|
185
|
+
_SQUEEZE_WRAP_RE = re.compile(
|
|
186
|
+
rb'<(?:[A-Za-z_][\w.-]*:)?subList\b[^>]*?\blineWrap="(?P<value>SQUEEZE)"'
|
|
187
|
+
)
|
|
185
188
|
|
|
186
189
|
def _first_paragraph_span(cell: bytes) -> tuple[int, int] | None:
|
|
187
190
|
"""Byte span of the cell's first ``<hp:p>...</hp:p>`` (its own subList's
|
|
@@ -196,6 +199,22 @@ def _all_paragraph_spans(cell: bytes) -> list[tuple[int, int]]:
|
|
|
196
199
|
return [(m.start(), m.end()) for m in _P_SPAN_RE.finditer(masked)]
|
|
197
200
|
|
|
198
201
|
|
|
202
|
+
def _squeeze_wrap_edit(cell: bytes) -> tuple[int, int, bytes] | None:
|
|
203
|
+
"""Return a minimal edit that makes a filled cell wrap instead of squeeze.
|
|
204
|
+
|
|
205
|
+
Hancom's ``lineWrap=SQUEEZE`` keeps long replacement text on the existing
|
|
206
|
+
line by compressing glyph advances. Template placeholders often fit, but
|
|
207
|
+
real filled values can become nearly unreadable even though their charPr
|
|
208
|
+
spacing is normal. Only the addressed cell's direct subList is considered;
|
|
209
|
+
nested tables remain untouched.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
match = _SQUEEZE_WRAP_RE.search(_mask_nested_tables(cell))
|
|
213
|
+
if match is None:
|
|
214
|
+
return None
|
|
215
|
+
return match.start("value"), match.end("value"), b"BREAK"
|
|
216
|
+
|
|
217
|
+
|
|
199
218
|
# --- font shrink-to-fit helpers (byte-preserving charPr materialisation) ------
|
|
200
219
|
|
|
201
220
|
def _header_part_name(parts: Mapping[str, bytes]) -> str | None:
|
|
@@ -602,6 +621,17 @@ def fill_cells(
|
|
|
602
621
|
continue
|
|
603
622
|
if not cell_edits:
|
|
604
623
|
continue
|
|
624
|
+
# A template's short placeholder may legitimately fit under
|
|
625
|
+
# lineWrap=SQUEEZE, while a real filled value is compressed until
|
|
626
|
+
# glyphs appear to overlap. Changed non-empty values must wrap and
|
|
627
|
+
# reflow; preserve SQUEEZE for no-op/clear operations.
|
|
628
|
+
if text.strip():
|
|
629
|
+
wrap_edit = _squeeze_wrap_edit(cell_bytes)
|
|
630
|
+
if wrap_edit is not None:
|
|
631
|
+
ws, we, replacement = wrap_edit
|
|
632
|
+
section_edits.append(
|
|
633
|
+
(ts + cell.start + ws, ts + cell.start + we, replacement)
|
|
634
|
+
)
|
|
605
635
|
section_edits.extend(cell_edits)
|
|
606
636
|
applied.append(CellApplied(section_path, ti, row, col, first_orig or "", text))
|
|
607
637
|
if section_edits:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-hwpx
|
|
3
|
-
Version: 2.24.
|
|
3
|
+
Version: 2.24.1
|
|
4
4
|
Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
|
|
5
5
|
Author: python-hwpx Maintainers
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -20,7 +20,7 @@ Requires-Python: >=3.10
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
License-File: NOTICE
|
|
23
|
-
Requires-Dist: lxml<
|
|
23
|
+
Requires-Dist: lxml<7,>=4.9
|
|
24
24
|
Provides-Extra: visual
|
|
25
25
|
Requires-Dist: pymupdf>=1.24; extra == "visual"
|
|
26
26
|
Requires-Dist: pillow>=10.0; extra == "visual"
|
|
@@ -202,6 +202,15 @@ pip install -e ".[dev]"
|
|
|
202
202
|
pytest
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
+
## 감사의 말
|
|
206
|
+
|
|
207
|
+
아래 공개 표준·프로젝트에 빚지고 있습니다.
|
|
208
|
+
|
|
209
|
+
- **[OWPML — 개방형 워드프로세서 마크업 언어 (KS X 6101)](https://www.kssn.net/search/stddetail.do?itemNo=K001010119985)** — HWPX가 기반하는 한국 산업 표준
|
|
210
|
+
- **[hancom-io/hwpx-owpml-model](https://github.com/hancom-io/hwpx-owpml-model)** — OWPML 요소 구조 참조 모델 · **[neolord0/hwpxlib](https://github.com/neolord0/hwpxlib)** — 오라클 샘플 코퍼스
|
|
211
|
+
- **[edwardkim/rhwp](https://github.com/edwardkim/rhwp)** — 멱등성·검증 게이트 설계 영감
|
|
212
|
+
- **범정부오피스** — 공무 문서 편집 워크플로 아이디어
|
|
213
|
+
|
|
205
214
|
## License
|
|
206
215
|
|
|
207
216
|
Apache License 2.0. See LICENSE and NOTICE.
|
|
@@ -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=
|
|
13
|
+
hwpx/table_patch.py,sha256=FCpCNQSX9jta12gmmSyDshB-okANYSL3O5YS0Rr1mX4,72358
|
|
14
14
|
hwpx/template_formfit.py,sha256=dlxf98FatT5Nl4hN15TuMXqj5NlDTGSnLaqXVo_PoBo,23424
|
|
15
15
|
hwpx/templates.py,sha256=28bYqeJVeDb1Cq8G9NZG9Mhnu4K2GamAKC4QhxvUZyA,1187
|
|
16
16
|
hwpx/builder/__init__.py,sha256=8tcxClbeuNle_R_2nDAauyy518OCegG8qVPjwIKRUZA,849
|
|
@@ -82,7 +82,7 @@ hwpx/opc/relationships.py,sha256=tPWLHRMlw0Spvtwou2jCDRfHdcm9FEKKLd95YVHLwYI,697
|
|
|
82
82
|
hwpx/opc/security.py,sha256=hsA73sZxUoGIgy2zue9EnV7ChHMfasnplmqzxFs3Mp4,4419
|
|
83
83
|
hwpx/opc/xml_utils.py,sha256=L_fHY1-D5I_TfdRkDQV-bn55EnXc6AqEDWItfMpawVs,3840
|
|
84
84
|
hwpx/oxml/__init__.py,sha256=7koxG5Xc6ia1dWmAqUJJETkAL5wzamSrNVcKuiUH58I,5466
|
|
85
|
-
hwpx/oxml/_document_impl.py,sha256=
|
|
85
|
+
hwpx/oxml/_document_impl.py,sha256=K4Wc_LNn6xanOF9n-DxIoWNjiXiNA5fGd469fx76kWs,250246
|
|
86
86
|
hwpx/oxml/body.py,sha256=3PzGiYmm03si5OVjGtS-R_tT1rWmsYwE8Ds8ZLhIIio,30609
|
|
87
87
|
hwpx/oxml/canonical_defaults.py,sha256=WHAK7u_W-PDv3P3N1-1-aWAoiUgBh4x-UybFL4NqW-w,3791
|
|
88
88
|
hwpx/oxml/common.py,sha256=TJkafzg7x4T3J29tZchRZk57ZTsrM9PEiqGT3rX3w5o,1044
|
|
@@ -161,10 +161,10 @@ hwpx/visual/diff.py,sha256=0X5T9IgwRZU3td-7vnPrlowovtGud7P_ymq0KVehlKk,5677
|
|
|
161
161
|
hwpx/visual/masks.py,sha256=oXhgynAb4uKjJtZ2BGHHdAjyvWGqSFlZFQ-iJxzHiuo,1832
|
|
162
162
|
hwpx/visual/oracle.py,sha256=VNO-tAB-lzTdW5XtSELxg_Aau369qRFBsJvNryHF_D8,31319
|
|
163
163
|
hwpx/visual/report.py,sha256=2RhXN1KBYOZTim9FNpeUhaaDHR7oFxI6Z2DLUkDIiwE,1717
|
|
164
|
-
python_hwpx-2.24.
|
|
165
|
-
python_hwpx-2.24.
|
|
166
|
-
python_hwpx-2.24.
|
|
167
|
-
python_hwpx-2.24.
|
|
168
|
-
python_hwpx-2.24.
|
|
169
|
-
python_hwpx-2.24.
|
|
170
|
-
python_hwpx-2.24.
|
|
164
|
+
python_hwpx-2.24.1.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
|
|
165
|
+
python_hwpx-2.24.1.dist-info/licenses/NOTICE,sha256=k48h6EaGQE8Y1c0dS9sIOOcz4YqkbcImWClF7pBOgsg,2473
|
|
166
|
+
python_hwpx-2.24.1.dist-info/METADATA,sha256=GAvO0M817KGuKIfRoMOErZl7m-89GoIUDMT0bCTfFDs,11399
|
|
167
|
+
python_hwpx-2.24.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
168
|
+
python_hwpx-2.24.1.dist-info/entry_points.txt,sha256=4U6WXYWHxEiWp2VRHo97fvOYNh7ebu6roonk7chxKcY,453
|
|
169
|
+
python_hwpx-2.24.1.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
|
|
170
|
+
python_hwpx-2.24.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|