python-hwpx 4.0.0__py3-none-any.whl → 4.1.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/form_fit/wordbox.py CHANGED
@@ -681,6 +681,14 @@ def extract_cell_clips(pdf_path: str, *, page: int | None = None) -> list[Rect]:
681
681
  These are the overflow clips — same coordinate space as the glyph boxes — so
682
682
  no HWPX→PDF transform is needed. ``find_tables`` can raise on odd pages; such
683
683
  a page contributes no clips rather than crashing.
684
+
685
+ Borders-only (``strategy="lines_strict"``): a cell rectangle is defined by its
686
+ *drawn borders*, not by the text inside it. The ``find_tables`` default snaps
687
+ edges to glyph positions, so a filled value can appear to *escape* a clip that
688
+ was mis-sized around the very text it holds — a false overflow. S-094 P3
689
+ measured this: the only 3 corpus pairs that flagged ``newOverflow`` (the nts
690
+ forms) all had the fill value escaping a text-snapped clip under the default,
691
+ and 0 escapes under ``lines_strict``; there were no real escapes to mask.
684
692
  """
685
693
 
686
694
  if not fitz_available():
@@ -695,7 +703,7 @@ def extract_cell_clips(pdf_path: str, *, page: int | None = None) -> list[Rect]:
695
703
  with doc:
696
704
  for pno in _page_indices(doc, page):
697
705
  try:
698
- tables = doc[pno].find_tables().tables
706
+ tables = doc[pno].find_tables(strategy="lines_strict").tables
699
707
  except Exception:
700
708
  continue # layout analysis failed on this page -> no clips, no crash
701
709
  for ti, table in enumerate(tables):
@@ -839,8 +847,21 @@ class LayoutSignature:
839
847
  lesson that absolute glyph-overlap is unusable on real forms). Page count is
840
848
  the dominant, high-confidence signal — a fill that spills onto a new page is
841
849
  the canonical layout collapse. Per-table ``(rows, cols)`` is the finer
842
- row/column signal; ``find_tables`` is content-sensitive, so it is judged as a
843
- multiset *delta* (blank vs filled), not an absolute count.
850
+ row/column signal, extracted from *drawn table borders only*
851
+ (``find_tables(strategy="lines_strict")``): a structural fingerprint must be
852
+ text-independent, so it is judged as a multiset *delta* (blank vs filled),
853
+ not an absolute count.
854
+
855
+ Why ``lines_strict`` and not the ``find_tables`` default (``"lines"``): the
856
+ default snaps table edges to *text* positions, so injecting a value into a
857
+ previously-empty cell makes it hallucinate a phantom ``(2,2)``/``(1,2)`` table
858
+ or wobble a real one by ±1 row/col even when the drawn grid and page count are
859
+ unchanged. S-094 P3 measured this on the frozen corpus (all 6 "table-shape"
860
+ differential failures were page-stable phantoms; under ``lines_strict`` blank
861
+ and filled agree, 0 regressions across 31 pairs; ``sen-24`` has byte-identical
862
+ drawn rectangles yet the default strategy still invented a ``(1,2)`` table from
863
+ the 3 added glyphs). Borders-only detection measures the grid the fill did not
864
+ touch.
844
865
  """
845
866
 
846
867
  page_count: int
@@ -879,7 +900,12 @@ def extract_layout_signature(pdf_path: str) -> LayoutSignature:
879
900
  for page in doc:
880
901
  sizes.append((float(page.rect.width), float(page.rect.height)))
881
902
  try:
882
- tables = page.find_tables().tables
903
+ # Borders-only ("lines_strict"): a *structural* fingerprint must
904
+ # not react to cell text. The default strategy snaps to glyph
905
+ # positions and invents phantom tables from a fill's added text
906
+ # (S-094 P3). Bordered form grids are detected identically either
907
+ # way; the text-sensitivity is the only difference we drop.
908
+ tables = page.find_tables(strategy="lines_strict").tables
883
909
  except Exception:
884
910
  continue # layout analysis failed on this page -> no tables, no crash
885
911
  for table in tables:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 4.0.0
3
+ Version: 4.1.1
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -108,7 +108,7 @@ hwpx/form_fit/measure.py,sha256=gnSfqccm7_3oTKv3HH6Zs77r2bToxzmfvUWN2zshDE8,2232
108
108
  hwpx/form_fit/policy.py,sha256=iXAatjS7ZycOdKgMCL4Q_kYg0qnogFPdRNlr_ecOvjc,3106
109
109
  hwpx/form_fit/report.py,sha256=h1NzQfbj1JYvZtKUi0DckJNWGnUHMZtQ3iCzbUxUjHA,3305
110
110
  hwpx/form_fit/seal.py,sha256=QsPzFagaEi7UKAXS-iFwiZs8rLG-_Fo9RixLc2OaqbU,17640
111
- hwpx/form_fit/wordbox.py,sha256=bStyzpcK4PF3pihRUSKiStwW_XwYHDeU0D3Or_Eh0nM,48301
111
+ hwpx/form_fit/wordbox.py,sha256=n86BegyBZMybf6Qxol6hWCG1r0EWiaJRyZEno_YkpIE,50170
112
112
  hwpx/ingest/__init__.py,sha256=cjDQwMdaqbq2xiD32zmaFAyzZbENga_6MLbgo0sLGZE,636
113
113
  hwpx/ingest/base.py,sha256=95jXJ70Hkay70BgyryGOzI3UVTixUpR-6f71iF3eqn4,8134
114
114
  hwpx/ingest/hwpx_converter.py,sha256=HOUCFYO-HK4WRpWiN5sA_kZIvdv439mkZ6PMCFU3hLg,4269
@@ -209,10 +209,10 @@ hwpx/visual/page_qa.py,sha256=AuJCySfLIdXjPeekhAc3YnrIWOsN0sI35Pnz8BZ6Pro,7278
209
209
  hwpx/visual/qa_contracts.py,sha256=1cjoiRTAWgi7NgE8SPc6bKxdoUfKx9nyou1mgC47TxY,10506
210
210
  hwpx/visual/qa_metrics.py,sha256=I7RdybN-f1Fvcv2j-ceDPoek51nOkMui1Zrd7TEX_C8,9838
211
211
  hwpx/visual/report.py,sha256=2RhXN1KBYOZTim9FNpeUhaaDHR7oFxI6Z2DLUkDIiwE,1717
212
- python_hwpx-4.0.0.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
213
- python_hwpx-4.0.0.dist-info/licenses/NOTICE,sha256=KJgtwIIzrXoA0j3PUhwp78ZtnucocEoB7jiuwoL4i7o,3060
214
- python_hwpx-4.0.0.dist-info/METADATA,sha256=bKvgcCFo1AJOMbkSGyeLDL6oP8z2blDqtP-JOElOgBo,9164
215
- python_hwpx-4.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
216
- python_hwpx-4.0.0.dist-info/entry_points.txt,sha256=PVUBTBQtBHiflQ9XBjfd004w-LrDibgZjwzxgu8Tx7w,480
217
- python_hwpx-4.0.0.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
218
- python_hwpx-4.0.0.dist-info/RECORD,,
212
+ python_hwpx-4.1.1.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
213
+ python_hwpx-4.1.1.dist-info/licenses/NOTICE,sha256=KJgtwIIzrXoA0j3PUhwp78ZtnucocEoB7jiuwoL4i7o,3060
214
+ python_hwpx-4.1.1.dist-info/METADATA,sha256=5R5nvsB-mwhZxnwU0KQG3wXscXzEBa6TjdvA4iknZhg,9164
215
+ python_hwpx-4.1.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
216
+ python_hwpx-4.1.1.dist-info/entry_points.txt,sha256=PVUBTBQtBHiflQ9XBjfd004w-LrDibgZjwzxgu8Tx7w,480
217
+ python_hwpx-4.1.1.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
218
+ python_hwpx-4.1.1.dist-info/RECORD,,