python-hwpx 2.21.0__tar.gz → 2.22.0__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.
Files changed (272) hide show
  1. {python_hwpx-2.21.0/src/python_hwpx.egg-info → python_hwpx-2.22.0}/PKG-INFO +1 -1
  2. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/pyproject.toml +1 -1
  3. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/table_patch.py +58 -0
  4. {python_hwpx-2.21.0 → python_hwpx-2.22.0/src/python_hwpx.egg-info}/PKG-INFO +1 -1
  5. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_table_patch.py +53 -0
  6. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/LICENSE +0 -0
  7. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/NOTICE +0 -0
  8. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/README.md +0 -0
  9. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/setup.cfg +0 -0
  10. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/__init__.py +0 -0
  11. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/authoring.py +0 -0
  12. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/builder/__init__.py +0 -0
  13. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/builder/core.py +0 -0
  14. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/builder/report.py +0 -0
  15. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/__init__.py +0 -0
  16. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/badges.py +0 -0
  17. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/corpus/corpus.json +0 -0
  18. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/corpus/meeting_summary.hwpx +0 -0
  19. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/corpus/notice.hwpx +0 -0
  20. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/corpus/report_table.hwpx +0 -0
  21. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/corpus.py +0 -0
  22. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/report.py +0 -0
  23. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/roundtrip_batch.py +0 -0
  24. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/conformance/runner.py +0 -0
  25. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/data/Skeleton.hwpx +0 -0
  26. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/__init__.py +0 -0
  27. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/_support.py +0 -0
  28. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/composer.py +0 -0
  29. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/harvest.py +0 -0
  30. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/plan.py +0 -0
  31. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profile.py +0 -0
  32. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/fragments/body.xml +0 -0
  33. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/fragments/heading.xml +0 -0
  34. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/fragments/info_table.xml +0 -0
  35. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/fragments/title.xml +0 -0
  36. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/profile.json +0 -0
  37. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/application_form/template.hwpx +0 -0
  38. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/home_notice/fragments/body.xml +0 -0
  39. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/home_notice/fragments/heading.xml +0 -0
  40. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/home_notice/fragments/title.xml +0 -0
  41. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/home_notice/profile.json +0 -0
  42. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/home_notice/template.hwpx +0 -0
  43. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/fragments/body.xml +0 -0
  44. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/fragments/heading.xml +0 -0
  45. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/fragments/info_table.xml +0 -0
  46. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/fragments/title.xml +0 -0
  47. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/profile.json +0 -0
  48. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/official_notice/template.hwpx +0 -0
  49. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/fragments/body.xml +0 -0
  50. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/fragments/heading.xml +0 -0
  51. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/fragments/info_table.xml +0 -0
  52. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/fragments/title.xml +0 -0
  53. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/profile.json +0 -0
  54. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/profiles/report/template.hwpx +0 -0
  55. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/design/validator.py +0 -0
  56. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/document.py +0 -0
  57. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/__init__.py +0 -0
  58. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/compose.py +0 -0
  59. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/ir.py +0 -0
  60. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/measure.py +0 -0
  61. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/parser.py +0 -0
  62. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/exam/profile.py +0 -0
  63. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fill.py +0 -0
  64. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/__init__.py +0 -0
  65. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/apply.py +0 -0
  66. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/engine.py +0 -0
  67. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/measure.py +0 -0
  68. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/policy.py +0 -0
  69. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/report.py +0 -0
  70. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/seal.py +0 -0
  71. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/form_fit/wordbox.py +0 -0
  72. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/layout/__init__.py +0 -0
  73. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/layout/lint.py +0 -0
  74. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/layout/report.py +0 -0
  75. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/opc/package.py +0 -0
  76. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/opc/relationships.py +0 -0
  77. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/opc/security.py +0 -0
  78. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/opc/xml_utils.py +0 -0
  79. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/__init__.py +0 -0
  80. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/_document_impl.py +0 -0
  81. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/body.py +0 -0
  82. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/canonical_defaults.py +0 -0
  83. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/common.py +0 -0
  84. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/document.py +0 -0
  85. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/header.py +0 -0
  86. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/header_part.py +0 -0
  87. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/memo.py +0 -0
  88. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/namespaces.py +0 -0
  89. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/numbering.py +0 -0
  90. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/objects.py +0 -0
  91. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/paragraph.py +0 -0
  92. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/parser.py +0 -0
  93. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/run.py +0 -0
  94. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/schema.py +0 -0
  95. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/section.py +0 -0
  96. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/simple_parts.py +0 -0
  97. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/table.py +0 -0
  98. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/oxml/utils.py +0 -0
  99. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/package.py +0 -0
  100. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/patch.py +0 -0
  101. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/presets/__init__.py +0 -0
  102. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/presets/proposal.py +0 -0
  103. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/py.typed +0 -0
  104. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/quality/__init__.py +0 -0
  105. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/quality/ledger.py +0 -0
  106. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/quality/policy.py +0 -0
  107. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/quality/report.py +0 -0
  108. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/quality/save_pipeline.py +0 -0
  109. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/template_formfit.py +0 -0
  110. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/templates.py +0 -0
  111. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/__init__.py +0 -0
  112. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/_schemas/header.xsd +0 -0
  113. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/_schemas/section.xsd +0 -0
  114. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/advanced_generators.py +0 -0
  115. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/archive_cli.py +0 -0
  116. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/doc_diff.py +0 -0
  117. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/exporter.py +0 -0
  118. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/__init__.py +0 -0
  119. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/__main__.py +0 -0
  120. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/catalog.py +0 -0
  121. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/generator.py +0 -0
  122. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/minimize.py +0 -0
  123. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/fuzz/runner.py +0 -0
  124. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/generic_inventory.py +0 -0
  125. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/id_integrity.py +0 -0
  126. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/idempotence.py +0 -0
  127. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/ir_equality.py +0 -0
  128. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/layout_preview.py +0 -0
  129. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/mail_merge.py +0 -0
  130. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/markdown_export.py +0 -0
  131. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/object_finder.py +0 -0
  132. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/official_lint.py +0 -0
  133. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/package_reconcile.py +0 -0
  134. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/package_validator.py +0 -0
  135. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/page_guard.py +0 -0
  136. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/pii.py +0 -0
  137. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/read_fidelity.py +0 -0
  138. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/recover.py +0 -0
  139. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/redline.py +0 -0
  140. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/repair.py +0 -0
  141. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/report_parser.py +0 -0
  142. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/report_utils.py +0 -0
  143. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/roundtrip_diff.py +0 -0
  144. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/style_profile.py +0 -0
  145. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/table_cleanup.py +0 -0
  146. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/table_compute.py +0 -0
  147. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/table_navigation.py +0 -0
  148. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/template_analyzer.py +0 -0
  149. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/text_extract_cli.py +0 -0
  150. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/text_extractor.py +0 -0
  151. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/toc_author.py +0 -0
  152. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/toc_fidelity.py +0 -0
  153. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/tools/validator.py +0 -0
  154. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/__init__.py +0 -0
  155. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/_hancom_open_rate.ps1 +0 -0
  156. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/_refresh_hwpx_mac.applescript +0 -0
  157. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/_render_hwpx.ps1 +0 -0
  158. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/_render_hwpx_mac.applescript +0 -0
  159. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/detectors.py +0 -0
  160. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/diff.py +0 -0
  161. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/masks.py +0 -0
  162. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/oracle.py +0 -0
  163. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/hwpx/visual/report.py +0 -0
  164. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/python_hwpx.egg-info/SOURCES.txt +0 -0
  165. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
  166. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/python_hwpx.egg-info/entry_points.txt +0 -0
  167. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/python_hwpx.egg-info/requires.txt +0 -0
  168. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/src/python_hwpx.egg-info/top_level.txt +0 -0
  169. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_advanced_generators.py +0 -0
  170. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_authoring_profile_routing.py +0 -0
  171. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_authoring_profile_routing_oracle.py +0 -0
  172. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_authoring_render_check.py +0 -0
  173. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_builder_core.py +0 -0
  174. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_builder_plan_v2.py +0 -0
  175. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_builder_vertical_slice.py +0 -0
  176. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_comment_node_robustness.py +0 -0
  177. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_conformance.py +0 -0
  178. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_corpus_read_fidelity.py +0 -0
  179. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_coverage_promotion.py +0 -0
  180. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_coverage_targets.py +0 -0
  181. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_design_builder.py +0 -0
  182. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_deviations_registry.py +0 -0
  183. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_doc_diff.py +0 -0
  184. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_document_context_manager.py +0 -0
  185. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_document_formatting.py +0 -0
  186. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_document_plan.py +0 -0
  187. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_document_plan_computed_fields.py +0 -0
  188. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_document_save_api.py +0 -0
  189. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_compose.py +0 -0
  190. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_compose_oracle.py +0 -0
  191. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_fixtures.py +0 -0
  192. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_ir.py +0 -0
  193. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_measure.py +0 -0
  194. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_parser.py +0 -0
  195. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_exam_profile.py +0 -0
  196. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_existing_document_format_editing.py +0 -0
  197. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fields.py +0 -0
  198. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fill_split_run.py +0 -0
  199. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fit.py +0 -0
  200. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fit_integration.py +0 -0
  201. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fit_seal.py +0 -0
  202. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fit_seal_placement.py +0 -0
  203. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_form_fit_wordbox.py +0 -0
  204. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_fuzz_loop.py +0 -0
  205. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_fuzz_regressions.py +0 -0
  206. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_gap_closure_tools.py +0 -0
  207. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_government_report_preset.py +0 -0
  208. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_government_table_profile.py +0 -0
  209. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_hp_tab_support.py +0 -0
  210. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_hwpxlib_corpus_read.py +0 -0
  211. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_id_generator_range.py +0 -0
  212. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_id_integrity.py +0 -0
  213. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_image_object_workflow.py +0 -0
  214. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_inline_models.py +0 -0
  215. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_integration_hwpx_compatibility.py +0 -0
  216. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_integration_roundtrip.py +0 -0
  217. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_kordoc_absorption.py +0 -0
  218. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_layout_lint.py +0 -0
  219. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_layout_preview.py +0 -0
  220. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_mail_merge_fit.py +0 -0
  221. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_mail_merge_table_compute.py +0 -0
  222. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_mail_merge_xlsx.py +0 -0
  223. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_markdown_export.py +0 -0
  224. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_memo_and_style_editing.py +0 -0
  225. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_namespace_handling.py +0 -0
  226. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_new_features.py +0 -0
  227. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_official_document_style.py +0 -0
  228. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_official_lint_gongmun_gate.py +0 -0
  229. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_official_lint_tableaware.py +0 -0
  230. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_opc_package.py +0 -0
  231. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_open_safety_corpus.py +0 -0
  232. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_openrate.py +0 -0
  233. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_oxml_parsing.py +0 -0
  234. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_packaging_license_metadata.py +0 -0
  235. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_packaging_py_typed.py +0 -0
  236. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_paragraph_keep_together.py +0 -0
  237. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_paragraph_section_management.py +0 -0
  238. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_pii.py +0 -0
  239. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_pii_structural.py +0 -0
  240. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_pii_wiring.py +0 -0
  241. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_proposal_preset.py +0 -0
  242. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_question_split_detector.py +0 -0
  243. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_read_fidelity.py +0 -0
  244. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_recover_broken_zip.py +0 -0
  245. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_redline_authoring.py +0 -0
  246. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_redline_verify.py +0 -0
  247. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_repair_repack.py +0 -0
  248. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_report_parser.py +0 -0
  249. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_report_utils.py +0 -0
  250. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_repr_snapshots.py +0 -0
  251. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_rhwp_t1_gates.py +0 -0
  252. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_rhwp_t2_verification.py +0 -0
  253. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_roundtrip_fidelity.py +0 -0
  254. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_save_pipeline.py +0 -0
  255. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_save_pipeline_no_bypass.py +0 -0
  256. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_section_headers.py +0 -0
  257. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_set_paragraph_format_keep.py +0 -0
  258. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_skeleton_template_ids.py +0 -0
  259. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_split_merged_cell.py +0 -0
  260. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_style_profile.py +0 -0
  261. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_table_cleanup.py +0 -0
  262. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_table_navigation.py +0 -0
  263. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_tables_default_border.py +0 -0
  264. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_template_analyzer_enrichment.py +0 -0
  265. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_template_formfit.py +0 -0
  266. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_text_extractor_annotations.py +0 -0
  267. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_toc_author.py +0 -0
  268. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_toc_fidelity.py +0 -0
  269. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_validation_severity.py +0 -0
  270. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_validator_comment_nodes.py +0 -0
  271. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_version_metadata.py +0 -0
  272. {python_hwpx-2.21.0 → python_hwpx-2.22.0}/tests/test_visual_oracle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.21.0
3
+ Version: 2.22.0
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-hwpx"
7
- version = "2.21.0"
7
+ version = "2.22.0"
8
8
  description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = "Apache-2.0"
@@ -600,6 +600,57 @@ def _insert_row_by_clone(table: str, ref_row: int, count: int = 1) -> str:
600
600
  return _rebuild(prefix, new_rows, suffix, rowcnt=len(new_rows))
601
601
 
602
602
 
603
+ def _set_column_widths(table: str, new_widths: dict[int, int]) -> str:
604
+ """Set logical column widths (HWPUNIT). Each cell's cellSz.width = sum of its
605
+ spanned columns' new widths. Byte-preserving cellSz edits; grid unchanged."""
606
+ _guard_flat(table)
607
+ prefix, rows, suffix = _parse_table(table)
608
+
609
+ def fix(tc: str):
610
+ ca = _si(tc, "cellAddr", "colAddr")
611
+ cs = _si(tc, "cellSpan", "colSpan") or 1
612
+ w = sum(int(new_widths.get(c, 0)) for c in range(ca, ca + cs))
613
+ if w > 0:
614
+ tc = _ss(tc, "cellSz", "width", w)
615
+ return tc
616
+
617
+ rows = [_map_cells(r, fix) for r in rows]
618
+ return _rebuild(prefix, rows, suffix)
619
+
620
+
621
+ def _autofit_columns(table: str, *, min_frac: float = 0.06, damp: float = 0.5) -> str:
622
+ """Rebalance column widths to content: content-heavy columns widen, light ones
623
+ narrow, table total width preserved. Demand = longest single-span cell's text
624
+ width (form_fit advance model), sqrt-damped so a paragraph column doesn't run
625
+ away; every column keeps a floor of *min_frac* of the total."""
626
+ from .form_fit.measure import estimate_text_width
627
+
628
+ prefix, rows, suffix = _parse_table(table)
629
+ cur = _uniform_col_widths(rows)
630
+ if cur is None:
631
+ raise TableStructureError("no uniform (all colSpan=1) row to autofit widths")
632
+ ncol = max(cur) + 1
633
+ total = sum(cur.values())
634
+ demand = {c: 0.0 for c in range(ncol)}
635
+ for r in rows:
636
+ for tc in _S_TC.findall(r):
637
+ if (_si(tc, "cellSpan", "colSpan") or 1) != 1:
638
+ continue
639
+ ca = _si(tc, "cellAddr", "colAddr")
640
+ txt = "".join(re.findall(r"<hp:t>(.*?)</hp:t>", tc, re.DOTALL))
641
+ demand[ca] = max(demand[ca], estimate_text_width(txt, 10.0))
642
+ weight = {c: max(demand[c], 1.0) ** damp for c in range(ncol)}
643
+ sw = sum(weight.values()) or 1.0
644
+ floor = total * min_frac
645
+ raw = {c: max(floor, total * weight[c] / sw) for c in range(ncol)}
646
+ scale = total / (sum(raw.values()) or 1.0)
647
+ new = {c: int(round(raw[c] * scale)) for c in range(ncol)}
648
+ # absorb rounding drift into the widest column so the total is exact
649
+ drift = total - sum(new.values())
650
+ new[max(new, key=lambda c: new[c])] += drift
651
+ return _set_column_widths(table, new)
652
+
653
+
603
654
  def _validate_or_raise(table: str) -> None:
604
655
  _grid, rep = build_grid(table.encode("utf-8"))
605
656
  if not rep.ok:
@@ -608,10 +659,17 @@ def _validate_or_raise(table: str) -> None:
608
659
 
609
660
  # --- section-level application (byte-region splice back) ----------------------
610
661
 
662
+ def _widths_arg(o: Mapping[str, Any]) -> dict[int, int]:
663
+ w = o["widths"]
664
+ return {int(k): int(v) for k, v in w.items()} if isinstance(w, Mapping) else {i: int(v) for i, v in enumerate(w)}
665
+
666
+
611
667
  _STRUCT_OPS = {
612
668
  "delete_column": lambda t, o: _collapse_empty_rows(_delete_columns(t, o["cols"] if "cols" in o else [o["col"]])),
613
669
  "delete_row": lambda t, o: _delete_rows(t, o["rows"] if "rows" in o else [o["row"]]),
614
670
  "insert_row_by_clone": lambda t, o: _insert_row_by_clone(t, o["ref_row"], int(o.get("count", 1))),
671
+ "set_column_widths": lambda t, o: _set_column_widths(t, _widths_arg(o)),
672
+ "autofit_columns": lambda t, o: _autofit_columns(t, min_frac=float(o.get("min_frac", 0.06)), damp=float(o.get("damp", 0.5))),
615
673
  }
616
674
 
617
675
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.21.0
3
+ Version: 2.22.0
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -320,3 +320,56 @@ def test_multiple_cells_same_table_no_overlap(merged):
320
320
  txt = _section(res.data)[1].decode("utf-8")
321
321
  # at least the distinct (non-merge-colliding) cells landed
322
322
  assert sum(f"V{i}" in txt for i in range(3)) >= 1
323
+
324
+
325
+ # --- P6: column-width fit (set_column_widths / autofit_columns) ---------------
326
+
327
+ def _uniform_row_table(data: bytes):
328
+ """Find a table with a uniform (all colSpan=1) row and >=3 columns."""
329
+ from hwpx.table_patch import _uniform_col_widths
330
+ sec, spans = _tables(data)
331
+ for ti, sp in enumerate(spans):
332
+ rows = _parse_table(sec[sp[0]:sp[1]].decode("utf-8"))[1]
333
+ w = _uniform_col_widths(rows)
334
+ if w and len(w) >= 3:
335
+ return ti, w
336
+ return None, None
337
+
338
+
339
+ def test_set_column_widths_preserves_total_and_grid(merged):
340
+ from hwpx.table_patch import _uniform_col_widths
341
+ ti, w = _uniform_row_table(merged)
342
+ if ti is None:
343
+ pytest.skip("no uniform multi-column table")
344
+ total = sum(w.values())
345
+ target = {c: total // len(w) for c in range(len(w))}
346
+ target[0] += total - sum(target.values()) # exact total
347
+ res = apply_table_ops(merged, [{"op": "set_column_widths", "table_index": ti, "widths": target}])
348
+ assert res.ok, res.skipped
349
+ sec2, spans2 = _tables(res.data)
350
+ rep = build_grid(sec2[spans2[ti][0]:spans2[ti][1]])[1]
351
+ assert rep.ok
352
+ new_w = _uniform_col_widths(_parse_table(sec2[spans2[ti][0]:spans2[ti][1]].decode("utf-8"))[1])
353
+ assert sum(new_w.values()) == total
354
+
355
+
356
+ def test_autofit_columns_widens_content_heavy(merged):
357
+ from hwpx.table_patch import _uniform_col_widths
358
+ ti, w = _uniform_row_table(merged)
359
+ if ti is None:
360
+ pytest.skip("no uniform multi-column table")
361
+ total = sum(w.values())
362
+ # make col 0 content-heavy, col 1 light, then autofit
363
+ long_txt = "가나다라마바사아자차카타파하" * 6
364
+ filled = fill_cells(merged, [
365
+ {"table_index": ti, "row": 0, "col": 0, "text": long_txt},
366
+ {"table_index": ti, "row": 0, "col": 1, "text": "짧"},
367
+ ])
368
+ res = apply_table_ops(filled.data, [{"op": "autofit_columns", "table_index": ti}])
369
+ assert res.ok, res.skipped
370
+ sec2, spans2 = _tables(res.data)
371
+ new_w = _uniform_col_widths(_parse_table(sec2[spans2[ti][0]:spans2[ti][1]].decode("utf-8"))[1])
372
+ assert new_w is not None
373
+ assert sum(new_w.values()) == total # total preserved
374
+ assert new_w[0] > new_w[1] # heavy column wider than light
375
+ assert build_grid(sec2[spans2[ti][0]:spans2[ti][1]])[1].ok
File without changes
File without changes
File without changes
File without changes