python-hwpx 2.29.1__tar.gz → 3.0.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 (355) hide show
  1. {python_hwpx-2.29.1/src/python_hwpx.egg-info → python_hwpx-3.0.0}/PKG-INFO +3 -2
  2. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/README.md +1 -1
  3. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/pyproject.toml +2 -1
  4. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/dump.py +0 -1
  5. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/native.py +0 -1
  6. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/benchmark/blind_eval.py +1 -1
  7. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/corpus/meeting_summary.hwpx +0 -0
  8. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/corpus/notice.hwpx +0 -0
  9. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/corpus/report_table.hwpx +0 -0
  10. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/data/Skeleton.hwpx +0 -0
  11. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/profile.json +2 -2
  12. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/document.py +4 -4
  13. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/evalplan_fill.py +3 -5
  14. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/seal.py +2 -3
  15. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/formfill_quality.py +0 -1
  16. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/__init__.py +2 -0
  17. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/_document_impl.py +6 -1
  18. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/body.py +1 -1
  19. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/document.py +0 -1
  20. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/header.py +2 -2
  21. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/table_patch.py +23 -1
  22. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/runner.py +0 -1
  23. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/toc_fidelity.py +1 -1
  24. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/detectors.py +1 -2
  25. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/hancom_worker.py +0 -1
  26. {python_hwpx-2.29.1 → python_hwpx-3.0.0/src/python_hwpx.egg-info}/PKG-INFO +3 -2
  27. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/python_hwpx.egg-info/SOURCES.txt +1 -26
  28. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/python_hwpx.egg-info/requires.txt +1 -0
  29. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_blueprint_contracts.py +1 -1
  30. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_body_patch.py +0 -1
  31. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_builder_core.py +4 -4
  32. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_conformance.py +0 -3
  33. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_corpus_read_fidelity.py +0 -1
  34. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_coverage_promotion.py +0 -1
  35. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_design_builder.py +24 -5
  36. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_document_plan_computed_fields.py +1 -1
  37. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_document_save_api.py +0 -1
  38. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_evalplan_fill.py +36 -1
  39. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_measure.py +0 -1
  40. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fit.py +0 -1
  41. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_formfill_quality.py +0 -1
  42. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_integration_roundtrip.py +0 -2
  43. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_markdown_export.py +3 -3
  44. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_new_features.py +3 -8
  45. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_official_lint_gongmun_gate.py +0 -1
  46. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_openrate.py +4 -4
  47. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_packaging_py_typed.py +4 -0
  48. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_paragraph_section_management.py +0 -2
  49. python_hwpx-3.0.0/tests/test_public_runtime_boundary.py +12 -0
  50. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_split_cell.py +0 -1
  51. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_split_merged_cell.py +0 -1
  52. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_table_patch.py +44 -0
  53. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_table_patch_m105.py +31 -0
  54. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_template_formfit.py +2 -2
  55. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_toc_author.py +0 -3
  56. python_hwpx-2.29.1/src/hwpx/practice/__init__.py +0 -277
  57. python_hwpx-2.29.1/src/hwpx/practice/aggregate.py +0 -947
  58. python_hwpx-2.29.1/src/hwpx/practice/campaign.py +0 -296
  59. python_hwpx-2.29.1/src/hwpx/practice/domain.py +0 -3137
  60. python_hwpx-2.29.1/src/hwpx/practice/dossier.py +0 -78
  61. python_hwpx-2.29.1/src/hwpx/practice/evaluator.py +0 -2359
  62. python_hwpx-2.29.1/src/hwpx/practice/forge.py +0 -436
  63. python_hwpx-2.29.1/src/hwpx/practice/intake.py +0 -230
  64. python_hwpx-2.29.1/src/hwpx/practice/lineage.py +0 -113
  65. python_hwpx-2.29.1/src/hwpx/practice/mutations.py +0 -168
  66. python_hwpx-2.29.1/src/hwpx/practice/registry.py +0 -322
  67. python_hwpx-2.29.1/src/hwpx/practice/run.py +0 -757
  68. python_hwpx-2.29.1/src/hwpx/practice/sanitize.py +0 -154
  69. python_hwpx-2.29.1/src/hwpx/practice/scenario.py +0 -146
  70. python_hwpx-2.29.1/src/hwpx/practice/split.py +0 -249
  71. python_hwpx-2.29.1/tests/test_practice_campaign_aggregate.py +0 -870
  72. python_hwpx-2.29.1/tests/test_practice_contracts.py +0 -255
  73. python_hwpx-2.29.1/tests/test_practice_domain_evaluator.py +0 -2134
  74. python_hwpx-2.29.1/tests/test_practice_evaluator.py +0 -2100
  75. python_hwpx-2.29.1/tests/test_practice_intake.py +0 -214
  76. python_hwpx-2.29.1/tests/test_practice_run_contracts.py +0 -422
  77. python_hwpx-2.29.1/tests/test_practice_sanitize.py +0 -75
  78. python_hwpx-2.29.1/tests/test_practice_scenario_forge.py +0 -73
  79. python_hwpx-2.29.1/tests/test_practice_scenario_pack.py +0 -170
  80. python_hwpx-2.29.1/tests/test_practice_source_integrity.py +0 -128
  81. python_hwpx-2.29.1/tests/test_practice_split.py +0 -85
  82. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/LICENSE +0 -0
  83. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/NOTICE +0 -0
  84. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/setup.cfg +0 -0
  85. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/__init__.py +0 -0
  86. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/__init__.py +0 -0
  87. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/__init__.py +0 -0
  88. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/bundle.py +0 -0
  89. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/catalog.py +0 -0
  90. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/mapping.py +0 -0
  91. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/model.py +0 -0
  92. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/blueprint/replay.py +0 -0
  93. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/catalog.py +0 -0
  94. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/cli.py +0 -0
  95. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/commands.py +0 -0
  96. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/document.py +0 -0
  97. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/model.py +0 -0
  98. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/path.py +0 -0
  99. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/agent/query.py +0 -0
  100. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/authoring.py +0 -0
  101. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/benchmark/__init__.py +0 -0
  102. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/body_patch.py +0 -0
  103. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/builder/__init__.py +0 -0
  104. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/builder/core.py +0 -0
  105. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/builder/report.py +0 -0
  106. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/__init__.py +0 -0
  107. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/badges.py +0 -0
  108. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/corpus/corpus.json +0 -0
  109. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/corpus.py +0 -0
  110. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/report.py +0 -0
  111. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/roundtrip_batch.py +0 -0
  112. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/conformance/runner.py +0 -0
  113. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/__init__.py +0 -0
  114. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/_support.py +0 -0
  115. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/composer.py +0 -0
  116. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/harvest.py +0 -0
  117. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/plan.py +0 -0
  118. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profile.py +0 -0
  119. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/fragments/body.xml +0 -0
  120. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/fragments/heading.xml +0 -0
  121. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/fragments/info_table.xml +0 -0
  122. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/fragments/title.xml +0 -0
  123. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/profile.json +0 -0
  124. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/application_form/template.hwpx +0 -0
  125. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/home_notice/fragments/body.xml +0 -0
  126. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/home_notice/fragments/heading.xml +0 -0
  127. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/home_notice/fragments/title.xml +0 -0
  128. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/home_notice/profile.json +0 -0
  129. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/home_notice/template.hwpx +0 -0
  130. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/fragments/body.xml +0 -0
  131. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/fragments/heading.xml +0 -0
  132. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/fragments/info_table.xml +0 -0
  133. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/fragments/title.xml +0 -0
  134. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/official_notice/template.hwpx +0 -0
  135. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/fragments/body.xml +0 -0
  136. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/fragments/heading.xml +0 -0
  137. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/fragments/info_table.xml +0 -0
  138. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/fragments/title.xml +0 -0
  139. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/profile.json +0 -0
  140. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/profiles/report/template.hwpx +0 -0
  141. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/design/validator.py +0 -0
  142. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/__init__.py +0 -0
  143. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/compose.py +0 -0
  144. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/ir.py +0 -0
  145. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/measure.py +0 -0
  146. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/parser.py +0 -0
  147. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/exam/profile.py +0 -0
  148. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/fill_residue.py +0 -0
  149. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fill.py +0 -0
  150. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/__init__.py +0 -0
  151. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/apply.py +0 -0
  152. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/engine.py +0 -0
  153. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/measure.py +0 -0
  154. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/policy.py +0 -0
  155. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/report.py +0 -0
  156. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/form_fit/wordbox.py +0 -0
  157. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/guidance_scan.py +0 -0
  158. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/ingest/__init__.py +0 -0
  159. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/ingest/base.py +0 -0
  160. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/ingest/hwpx_converter.py +0 -0
  161. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/layout/__init__.py +0 -0
  162. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/layout/lint.py +0 -0
  163. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/layout/report.py +0 -0
  164. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/opc/package.py +0 -0
  165. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/opc/relationships.py +0 -0
  166. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/opc/security.py +0 -0
  167. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/opc/xml_utils.py +0 -0
  168. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/canonical_defaults.py +0 -0
  169. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/common.py +0 -0
  170. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/header_part.py +0 -0
  171. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/memo.py +0 -0
  172. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/namespaces.py +0 -0
  173. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/numbering.py +0 -0
  174. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/objects.py +0 -0
  175. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/paragraph.py +0 -0
  176. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/parser.py +0 -0
  177. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/run.py +0 -0
  178. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/schema.py +0 -0
  179. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/section.py +0 -0
  180. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/simple_parts.py +0 -0
  181. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/table.py +0 -0
  182. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/oxml/utils.py +0 -0
  183. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/package.py +0 -0
  184. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/patch.py +0 -0
  185. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/presets/__init__.py +0 -0
  186. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/presets/proposal.py +0 -0
  187. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/py.typed +0 -0
  188. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/quality/__init__.py +0 -0
  189. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/quality/ledger.py +0 -0
  190. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/quality/policy.py +0 -0
  191. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/quality/report.py +0 -0
  192. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/quality/save_pipeline.py +0 -0
  193. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/template_formfit.py +0 -0
  194. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/templates.py +0 -0
  195. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/__init__.py +0 -0
  196. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/_schemas/header.xsd +0 -0
  197. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/_schemas/section.xsd +0 -0
  198. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/advanced_generators.py +0 -0
  199. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/archive_cli.py +0 -0
  200. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/doc_diff.py +0 -0
  201. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/exporter.py +0 -0
  202. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/__init__.py +0 -0
  203. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/__main__.py +0 -0
  204. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/catalog.py +0 -0
  205. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/generator.py +0 -0
  206. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/fuzz/minimize.py +0 -0
  207. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/generic_inventory.py +0 -0
  208. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/id_integrity.py +0 -0
  209. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/idempotence.py +0 -0
  210. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/ir_equality.py +0 -0
  211. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/layout_preview.py +0 -0
  212. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/mail_merge.py +0 -0
  213. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/markdown_export.py +0 -0
  214. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/object_finder.py +0 -0
  215. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/official_lint.py +0 -0
  216. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/package_reconcile.py +0 -0
  217. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/package_validator.py +0 -0
  218. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/page_guard.py +0 -0
  219. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/pii.py +0 -0
  220. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/read_fidelity.py +0 -0
  221. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/recover.py +0 -0
  222. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/redline.py +0 -0
  223. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/repair.py +0 -0
  224. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/report_parser.py +0 -0
  225. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/report_utils.py +0 -0
  226. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/roundtrip_diff.py +0 -0
  227. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/style_profile.py +0 -0
  228. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/table_cleanup.py +0 -0
  229. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/table_compute.py +0 -0
  230. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/table_navigation.py +0 -0
  231. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/template_analyzer.py +0 -0
  232. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/text_extract_cli.py +0 -0
  233. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/text_extractor.py +0 -0
  234. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/toc_author.py +0 -0
  235. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/tools/validator.py +0 -0
  236. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/__init__.py +0 -0
  237. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/_hancom_open_rate.ps1 +0 -0
  238. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/_refresh_hwpx_mac.applescript +0 -0
  239. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/_render_hwpx.ps1 +0 -0
  240. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/_render_hwpx_mac.applescript +0 -0
  241. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/diff.py +0 -0
  242. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/fixture_corpus.py +0 -0
  243. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/masks.py +0 -0
  244. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/oracle.py +0 -0
  245. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/page_qa.py +0 -0
  246. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/qa_contracts.py +0 -0
  247. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/qa_metrics.py +0 -0
  248. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/hwpx/visual/report.py +0 -0
  249. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
  250. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/python_hwpx.egg-info/entry_points.txt +0 -0
  251. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/src/python_hwpx.egg-info/top_level.txt +0 -0
  252. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_advanced_generators.py +0 -0
  253. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_blueprint_dump.py +0 -0
  254. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_blueprint_replay.py +0 -0
  255. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_catalog.py +0 -0
  256. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_cli.py +0 -0
  257. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_commands.py +0 -0
  258. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_contracts.py +0 -0
  259. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_document.py +0 -0
  260. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_agent_path_query.py +0 -0
  261. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_authoring_profile_routing.py +0 -0
  262. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_authoring_profile_routing_oracle.py +0 -0
  263. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_authoring_render_check.py +0 -0
  264. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_blind_eval_fixture.py +0 -0
  265. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_builder_plan_v2.py +0 -0
  266. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_builder_vertical_slice.py +0 -0
  267. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_cell_line_spacing.py +0 -0
  268. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_comment_node_robustness.py +0 -0
  269. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_coverage_targets.py +0 -0
  270. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_deviations_registry.py +0 -0
  271. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_doc_diff.py +0 -0
  272. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_document_context_manager.py +0 -0
  273. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_document_formatting.py +0 -0
  274. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_document_plan.py +0 -0
  275. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_compose.py +0 -0
  276. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_compose_oracle.py +0 -0
  277. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_fixtures.py +0 -0
  278. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_ir.py +0 -0
  279. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_parser.py +0 -0
  280. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_exam_profile.py +0 -0
  281. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_existing_document_format_editing.py +0 -0
  282. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_fill_residue.py +0 -0
  283. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fields.py +0 -0
  284. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fill_split_run.py +0 -0
  285. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fit_integration.py +0 -0
  286. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fit_seal.py +0 -0
  287. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fit_seal_placement.py +0 -0
  288. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_form_fit_wordbox.py +0 -0
  289. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_fuzz_loop.py +0 -0
  290. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_fuzz_regressions.py +0 -0
  291. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_gap_closure_tools.py +0 -0
  292. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_government_report_preset.py +0 -0
  293. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_government_table_profile.py +0 -0
  294. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_guidance_scan.py +0 -0
  295. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_hancom_render_worker.py +0 -0
  296. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_hp_tab_support.py +0 -0
  297. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_hwpxlib_corpus_read.py +0 -0
  298. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_id_generator_range.py +0 -0
  299. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_id_integrity.py +0 -0
  300. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_image_object_workflow.py +0 -0
  301. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_ingest.py +0 -0
  302. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_inline_models.py +0 -0
  303. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_integration_hwpx_compatibility.py +0 -0
  304. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_kordoc_absorption.py +0 -0
  305. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_layout_lint.py +0 -0
  306. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_layout_preview.py +0 -0
  307. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_mail_merge_fit.py +0 -0
  308. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_mail_merge_table_compute.py +0 -0
  309. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_mail_merge_xlsx.py +0 -0
  310. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_memo_and_style_editing.py +0 -0
  311. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_namespace_handling.py +0 -0
  312. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_official_document_style.py +0 -0
  313. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_official_lint_tableaware.py +0 -0
  314. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_opc_package.py +0 -0
  315. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_open_safety_corpus.py +0 -0
  316. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_oxml_parsing.py +0 -0
  317. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_packaging_license_metadata.py +0 -0
  318. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_paragraph_keep_together.py +0 -0
  319. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_pii.py +0 -0
  320. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_pii_structural.py +0 -0
  321. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_pii_wiring.py +0 -0
  322. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_proposal_preset.py +0 -0
  323. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_question_split_detector.py +0 -0
  324. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_read_fidelity.py +0 -0
  325. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_recover_broken_zip.py +0 -0
  326. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_redline_authoring.py +0 -0
  327. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_redline_verify.py +0 -0
  328. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_repair_repack.py +0 -0
  329. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_report_parser.py +0 -0
  330. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_report_utils.py +0 -0
  331. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_repr_snapshots.py +0 -0
  332. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_rhwp_t1_gates.py +0 -0
  333. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_rhwp_t2_verification.py +0 -0
  334. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_roundtrip_fidelity.py +0 -0
  335. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_row_heights.py +0 -0
  336. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_save_pipeline.py +0 -0
  337. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_save_pipeline_no_bypass.py +0 -0
  338. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_section_headers.py +0 -0
  339. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_set_paragraph_format_keep.py +0 -0
  340. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_skeleton_template_ids.py +0 -0
  341. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_style_profile.py +0 -0
  342. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_table_cleanup.py +0 -0
  343. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_table_navigation.py +0 -0
  344. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_table_patch_dryrun.py +0 -0
  345. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_tables_default_border.py +0 -0
  346. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_template_analyzer_enrichment.py +0 -0
  347. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_text_extractor_annotations.py +0 -0
  348. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_toc_fidelity.py +0 -0
  349. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_validation_severity.py +0 -0
  350. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_validator_comment_nodes.py +0 -0
  351. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_version_metadata.py +0 -0
  352. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_visual_fixture_corpus.py +0 -0
  353. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_visual_oracle.py +0 -0
  354. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_visual_qa_contracts.py +0 -0
  355. {python_hwpx-2.29.1 → python_hwpx-3.0.0}/tests/test_visual_qa_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.29.1
3
+ Version: 3.0.0
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -37,6 +37,7 @@ Requires-Dist: numpy>=1.26; extra == "test"
37
37
  Requires-Dist: pillow>=10.0; extra == "test"
38
38
  Requires-Dist: pytest>=7.4; extra == "test"
39
39
  Requires-Dist: pytest-cov>=5.0; extra == "test"
40
+ Requires-Dist: ruff>=0.12; extra == "test"
40
41
  Provides-Extra: typecheck
41
42
  Requires-Dist: mypy>=1.10; extra == "typecheck"
42
43
  Requires-Dist: pyright>=1.1.390; extra == "typecheck"
@@ -219,7 +220,7 @@ Apache License 2.0. See LICENSE and NOTICE.
219
220
 
220
221
  ## Maintainer
221
222
 
222
- Primary maintainer/contact: **고규현** — 광교고등학교 정보·컴퓨터 교사
223
+ Primary maintainer/contact: **Kohkyuhyun** ([@airmang](https://github.com/airmang))
223
224
 
224
225
  - ✉️ [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
225
226
  - 🐙 [@airmang](https://github.com/airmang)
@@ -175,7 +175,7 @@ Apache License 2.0. See LICENSE and NOTICE.
175
175
 
176
176
  ## Maintainer
177
177
 
178
- Primary maintainer/contact: **고규현** — 광교고등학교 정보·컴퓨터 교사
178
+ Primary maintainer/contact: **Kohkyuhyun** ([@airmang](https://github.com/airmang))
179
179
 
180
180
  - ✉️ [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
181
181
  - 🐙 [@airmang](https://github.com/airmang)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-hwpx"
7
- version = "2.29.1"
7
+ version = "3.0.0"
8
8
  description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = "Apache-2.0"
@@ -49,6 +49,7 @@ test = [
49
49
  "pillow>=10.0",
50
50
  "pytest>=7.4",
51
51
  "pytest-cov>=5.0",
52
+ "ruff>=0.12",
52
53
  ]
53
54
  typecheck = [
54
55
  "mypy>=1.10",
@@ -16,7 +16,6 @@ from ..document import HwpxAgentDocument, NodeRecord
16
16
  from ..model import AGENT_CATALOG_SCHEMA, NODE_KINDS, AgentContractError
17
17
  from .bundle import (
18
18
  ALLOWED_MEDIA_TYPES,
19
- BlueprintBundle,
20
19
  build_blueprint_bundle,
21
20
  read_blueprint_bundle,
22
21
  write_blueprint_bundle,
@@ -11,7 +11,6 @@ from dataclasses import dataclass
11
11
  from typing import Any
12
12
 
13
13
  from hwpx.document import HwpxDocument
14
- from hwpx.oxml import HwpxOxmlTable
15
14
  from hwpx.oxml.namespaces import HH, HP
16
15
 
17
16
  from ..commands import _add, _insert_direct_child, _insert_inline, _remove_inline_element, _table_caption
@@ -12,7 +12,7 @@ import json
12
12
  import math
13
13
  from collections import Counter, defaultdict
14
14
  from pathlib import Path
15
- from typing import Any, Mapping, Sequence
15
+ from typing import Any, Mapping
16
16
 
17
17
  BENCHMARK_SCHEMA = "hwpx.blind-real-work-eval/v1"
18
18
  RESULT_SCHEMA = "hwpx.blind-real-work-eval-result/v1"
@@ -21,5 +21,5 @@
21
21
  },
22
22
  "char_pr_count": 65,
23
23
  "style_coverage_threshold": 0.98,
24
- "source_basename": "경기도교육청 미래교육담당관_교육용 상용클라우드서비스 이용 안내.hwpx"
25
- }
24
+ "source_basename": "synthetic_official_notice_source.hwpx"
25
+ }
@@ -5,19 +5,16 @@ from __future__ import annotations
5
5
 
6
6
  import xml.etree.ElementTree as ET
7
7
  import io
8
- import os
9
8
  import re
10
- import tempfile
11
9
  import warnings
12
10
  from datetime import datetime
13
11
  import logging
14
12
  import uuid
15
13
 
16
14
  from os import PathLike
17
- from pathlib import Path, PurePosixPath
15
+ from pathlib import PurePosixPath
18
16
  from typing import TYPE_CHECKING, Any, BinaryIO, Iterator, Mapping, Sequence, overload
19
17
 
20
- from lxml import etree
21
18
 
22
19
  from .oxml import (
23
20
  Bullet,
@@ -65,6 +62,9 @@ _HWP_UNITS_PER_PT = 100
65
62
  logger = logging.getLogger(__name__)
66
63
 
67
64
  if TYPE_CHECKING:
65
+ from .form_fit.policy import FitPolicy
66
+ from .form_fit.report import FitResult
67
+ from .tools.validator import ValidationReport
68
68
  from .tools.table_navigation import TableFillResult, TableLabelSearchResult, TableMapResult
69
69
 
70
70
 
@@ -18,7 +18,7 @@ from __future__ import annotations
18
18
 
19
19
  import re
20
20
  from dataclasses import dataclass, field
21
- from typing import Any
21
+ from typing import Any, Sequence
22
22
 
23
23
  _CIRCLED = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮"
24
24
 
@@ -327,7 +327,7 @@ def _pick_achieve_rate(tabs, want_bands: int | None) -> int | None:
327
327
 
328
328
  def _regular_exam_cols(table) -> list[int]:
329
329
  """Logical column indices of the 정기시험 span in a 반영비율 table header."""
330
- from .table_patch import build_grid, _direct_cells, _text_of
330
+ from .table_patch import build_grid, _text_of
331
331
  tb = table.bytes
332
332
  grid, rep = build_grid(tb)
333
333
  cols: list[int] = []
@@ -1084,7 +1084,7 @@ def fill_rubrics(data: bytes, content: EvalPlanContent) -> tuple[bytes, dict[str
1084
1084
  cells (title / points / 성취기준 / A~E / 수행과제 / 평가요소 leaders / 기본점수 배점),
1085
1085
  reshapes+fills the 수행수준 채점기준 ladder, and rewrites each rubric's ordinal
1086
1086
  heading paragraph (가./나./다. + sample project title) to the review 영역명."""
1087
- from .table_patch import apply_table_ops, fill_cells, _text_of, _all_paragraph_spans
1087
+ from .table_patch import apply_table_ops, fill_cells, _all_paragraph_spans
1088
1088
 
1089
1089
  report: dict[str, Any] = {"rubrics": len(content.rubrics), "filled": 0, "skipped": []}
1090
1090
  levels = content.levels
@@ -1122,7 +1122,6 @@ def fill_rubrics(data: bytes, content: EvalPlanContent) -> tuple[bytes, dict[str
1122
1122
  if hdr is None or base is None:
1123
1123
  report["skipped"].append(f"rubric {i}: could not bound item block")
1124
1124
  continue
1125
- item_rows = base - (hdr + 1) # blank example block height (7)
1126
1125
  first_item = hdr + 1
1127
1126
  todel = list(range(first_item + n, base)) # keep n, drop the surplus
1128
1127
  if todel:
@@ -1471,7 +1470,6 @@ def fill_ratio(data: bytes, content: EvalPlanContent) -> tuple[bytes, dict[str,
1471
1470
  return data, report
1472
1471
  _sp, tb, grid, rep = _grid_of(data, ti)
1473
1472
  label_col, area_cols, total_col = _ratio_columns(tb, grid, rep)
1474
- areas = _area_names(content)
1475
1473
  if not area_cols:
1476
1474
  report["skipped"].append(f"no area columns detected (label_col={label_col}, total_col={total_col})")
1477
1475
  return data, report
@@ -32,7 +32,7 @@ point is exactly ``100`` HWPUNIT (``7200 / 72``).
32
32
  from __future__ import annotations
33
33
 
34
34
  import math
35
- from dataclasses import dataclass, field
35
+ from dataclasses import dataclass
36
36
  from typing import Any, Sequence
37
37
 
38
38
  from .wordbox import Rect, WordBox
@@ -219,8 +219,7 @@ def check_seal_placement(
219
219
  offset = math.hypot(scx - acx, scy - acy)
220
220
  centered = offset <= tol_pt
221
221
 
222
- # Glyphs the seal sits on top of, excluding the anchor's own line (intended).
223
- anchor_line = set(_norm(anchor.line_text)) # cheap line-membership proxy by text
222
+ # Glyphs the seal sits on top of, excluding the anchor's own baseline.
224
223
  anchor_cy = anchor.center[1]
225
224
  occluded = 0
226
225
  for g in boxes:
@@ -36,7 +36,6 @@ from pathlib import Path
36
36
  from typing import Any, Sequence
37
37
 
38
38
  from .table_patch import (
39
- _direct_cells,
40
39
  _iter_table_spans,
41
40
  _read_source_bytes,
42
41
  _sections,
@@ -135,11 +135,13 @@ __all__ = [
135
135
  "HwpxOxmlMasterPage",
136
136
  "HwpxOxmlMemo",
137
137
  "HwpxOxmlMemoGroup",
138
+ "HwpxOxmlNote",
138
139
  "HwpxOxmlParagraph",
139
140
  "HwpxOxmlRun",
140
141
  "HwpxOxmlSection",
141
142
  "HwpxOxmlSectionHeaderFooter",
142
143
  "HwpxOxmlSectionProperties",
144
+ "HwpxOxmlShape",
143
145
  "HwpxOxmlTable",
144
146
  "HwpxOxmlTableCell",
145
147
  "HwpxTableGridPosition",
@@ -7,7 +7,7 @@ import logging
7
7
  import re as _re
8
8
  from copy import deepcopy
9
9
  from dataclasses import dataclass
10
- from typing import Any, Callable, Iterable, Iterator, Mapping, Optional, Sequence, TypeVar
10
+ from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator, Mapping, Optional, Sequence, TypeVar
11
11
  from uuid import uuid4
12
12
  import xml.etree.ElementTree as ET
13
13
 
@@ -52,6 +52,11 @@ from .namespaces import (
52
52
  )
53
53
  from .utils import parse_int
54
54
 
55
+ if TYPE_CHECKING:
56
+ from hwpx.form_fit.policy import FitPolicy
57
+ from hwpx.form_fit.report import FitResult
58
+ from hwpx.opc.package import HwpxPackage
59
+
55
60
  register_owpml_namespaces(ET.register_namespace)
56
61
  logger = logging.getLogger(__name__)
57
62
 
@@ -7,7 +7,7 @@ from typing import Dict, List, Optional, Union
7
7
 
8
8
  from lxml import etree
9
9
 
10
- from .common import GenericElement, parse_generic_element
10
+ from .common import GenericElement
11
11
  from .namespaces import HP
12
12
  from .utils import local_name, parse_bool, parse_int
13
13
 
@@ -13,7 +13,6 @@ from types import ModuleType
13
13
 
14
14
  from . import _document_impl as _impl
15
15
  from ._document_impl import * # noqa: F401,F403
16
- from ._document_impl import _memo_id, _object_id, _paragraph_id
17
16
 
18
17
  __all__ = [name for name in dir(_impl) if not name.startswith("_")]
19
18
 
@@ -1480,7 +1480,7 @@ def track_change_to_xml(change: TrackChange) -> etree._Element:
1480
1480
  _set_optional_int_attr(attributes, "id", change.id)
1481
1481
  if change.raw_id is not None and change.id is None:
1482
1482
  attributes["id"] = change.raw_id
1483
- return etree.Element(f"{{http://www.hancom.co.kr/hwpml/2011/head}}trackChange", attributes)
1483
+ return etree.Element("{http://www.hancom.co.kr/hwpml/2011/head}trackChange", attributes)
1484
1484
 
1485
1485
 
1486
1486
  def track_change_author_to_xml(author: TrackChangeAuthor) -> etree._Element:
@@ -1496,7 +1496,7 @@ def track_change_author_to_xml(author: TrackChangeAuthor) -> etree._Element:
1496
1496
  attributes["id"] = author.raw_id
1497
1497
  _set_optional_str_attr(attributes, "color", author.color)
1498
1498
  return etree.Element(
1499
- f"{{http://www.hancom.co.kr/hwpml/2011/head}}trackChangeAuthor",
1499
+ "{http://www.hancom.co.kr/hwpml/2011/head}trackChangeAuthor",
1500
1500
  attributes,
1501
1501
  )
1502
1502
 
@@ -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
@@ -8,7 +8,6 @@ import logging
8
8
  import shutil
9
9
  import tempfile
10
10
  from contextlib import contextmanager
11
- from copy import deepcopy
12
11
  from dataclasses import dataclass
13
12
  from pathlib import Path
14
13
  from random import Random
@@ -24,7 +24,7 @@ from __future__ import annotations
24
24
  import re
25
25
  from dataclasses import dataclass, field
26
26
  from pathlib import Path
27
- from typing import Any, Sequence
27
+ from typing import Any
28
28
 
29
29
  from hwpx.document import HwpxDocument
30
30
 
@@ -14,7 +14,7 @@ gate on :func:`imaging_available` and degrade otherwise.
14
14
  """
15
15
  from __future__ import annotations
16
16
 
17
- from typing import TYPE_CHECKING, Any
17
+ from typing import TYPE_CHECKING
18
18
 
19
19
  if TYPE_CHECKING: # pragma: no cover - typing only
20
20
  from PIL import Image
@@ -88,7 +88,6 @@ def new_ink_ratio_outside_mask(before: "Image.Image", after: "Image.Image", rect
88
88
  output but not the original, in a region the edit was not allowed to paint.
89
89
  """
90
90
 
91
- import numpy as np
92
91
 
93
92
  before, after = _match_size(before, after)
94
93
  new_ink = _ink_mask(after) & ~_ink_mask(before)
@@ -5,7 +5,6 @@ from __future__ import annotations
5
5
 
6
6
  import hashlib
7
7
  import json
8
- import os
9
8
  import shutil
10
9
  import subprocess
11
10
  import tempfile
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.29.1
3
+ Version: 3.0.0
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -37,6 +37,7 @@ Requires-Dist: numpy>=1.26; extra == "test"
37
37
  Requires-Dist: pillow>=10.0; extra == "test"
38
38
  Requires-Dist: pytest>=7.4; extra == "test"
39
39
  Requires-Dist: pytest-cov>=5.0; extra == "test"
40
+ Requires-Dist: ruff>=0.12; extra == "test"
40
41
  Provides-Extra: typecheck
41
42
  Requires-Dist: mypy>=1.10; extra == "typecheck"
42
43
  Requires-Dist: pyright>=1.1.390; extra == "typecheck"
@@ -219,7 +220,7 @@ Apache License 2.0. See LICENSE and NOTICE.
219
220
 
220
221
  ## Maintainer
221
222
 
222
- Primary maintainer/contact: **고규현** — 광교고등학교 정보·컴퓨터 교사
223
+ Primary maintainer/contact: **Kohkyuhyun** ([@airmang](https://github.com/airmang))
223
224
 
224
225
  - ✉️ [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
225
226
  - 🐙 [@airmang](https://github.com/airmang)
@@ -123,21 +123,6 @@ src/hwpx/oxml/section.py
123
123
  src/hwpx/oxml/simple_parts.py
124
124
  src/hwpx/oxml/table.py
125
125
  src/hwpx/oxml/utils.py
126
- src/hwpx/practice/__init__.py
127
- src/hwpx/practice/aggregate.py
128
- src/hwpx/practice/campaign.py
129
- src/hwpx/practice/domain.py
130
- src/hwpx/practice/dossier.py
131
- src/hwpx/practice/evaluator.py
132
- src/hwpx/practice/forge.py
133
- src/hwpx/practice/intake.py
134
- src/hwpx/practice/lineage.py
135
- src/hwpx/practice/mutations.py
136
- src/hwpx/practice/registry.py
137
- src/hwpx/practice/run.py
138
- src/hwpx/practice/sanitize.py
139
- src/hwpx/practice/scenario.py
140
- src/hwpx/practice/split.py
141
126
  src/hwpx/presets/__init__.py
142
127
  src/hwpx/presets/proposal.py
143
128
  src/hwpx/quality/__init__.py
@@ -299,18 +284,8 @@ tests/test_paragraph_section_management.py
299
284
  tests/test_pii.py
300
285
  tests/test_pii_structural.py
301
286
  tests/test_pii_wiring.py
302
- tests/test_practice_campaign_aggregate.py
303
- tests/test_practice_contracts.py
304
- tests/test_practice_domain_evaluator.py
305
- tests/test_practice_evaluator.py
306
- tests/test_practice_intake.py
307
- tests/test_practice_run_contracts.py
308
- tests/test_practice_sanitize.py
309
- tests/test_practice_scenario_forge.py
310
- tests/test_practice_scenario_pack.py
311
- tests/test_practice_source_integrity.py
312
- tests/test_practice_split.py
313
287
  tests/test_proposal_preset.py
288
+ tests/test_public_runtime_boundary.py
314
289
  tests/test_question_split_detector.py
315
290
  tests/test_read_fidelity.py
316
291
  tests/test_recover_broken_zip.py
@@ -11,6 +11,7 @@ numpy>=1.26
11
11
  pillow>=10.0
12
12
  pytest>=7.4
13
13
  pytest-cov>=5.0
14
+ ruff>=0.12
14
15
 
15
16
  [typecheck]
16
17
  mypy>=1.10
@@ -132,7 +132,7 @@ def test_manifest_rejects_hash_mismatch_and_absolute_private_label() -> None:
132
132
  with pytest.raises(AgentContractError):
133
133
  validate_blueprint_manifest(manifest)
134
134
  manifest = _manifest()
135
- manifest["source"]["label"] = "/Users/private/source.hwpx"
135
+ manifest["source"]["label"] = "/workspace/private/source.hwpx"
136
136
  manifest = with_blueprint_hash(manifest)
137
137
  with pytest.raises(AgentContractError):
138
138
  validate_blueprint_manifest(manifest)
@@ -211,7 +211,6 @@ def test_strip_runs_by_color_reaches_cells(work, tmp_path):
211
211
 
212
212
  def test_recolor_runs_exact_hex(work, tmp_path):
213
213
  """정확 hex 매칭으로 재색 — 계열 다른 디자인색은 불변."""
214
- import hwpx.guidance_scan as gs
215
214
  from hwpx.body_patch import recolor_runs_by_color
216
215
  from hwpx.fill_residue import _scan_paragraphs
217
216
  out = tmp_path / "out.hwpx"
@@ -197,7 +197,7 @@ def test_document_ensure_run_style_supports_rich_char_properties() -> None:
197
197
  }
198
198
 
199
199
 
200
- def test_builder_lowers_rich_runs_and_reopen_preserves_style(tmp_path) -> None:
200
+ def test_builder_lowers_korean_rich_run_and_reopen_preserves_style(tmp_path) -> None:
201
201
  from hwpx.builder import Document, Paragraph, Run, Section
202
202
 
203
203
  path = tmp_path / "builder-rich-run.hwpx"
@@ -280,7 +280,7 @@ def test_ensure_run_style_supports_rich_char_properties() -> None:
280
280
  assert style.child_attributes["strikeout"]["shape"] == "SOLID"
281
281
 
282
282
 
283
- def test_builder_lowers_rich_runs_and_reopen_preserves_style(tmp_path) -> None:
283
+ def test_builder_lowers_mixed_rich_runs_and_reopen_preserves_style(tmp_path) -> None:
284
284
  from hwpx.builder import Document, Paragraph, Run, Section
285
285
 
286
286
  path = tmp_path / "builder-rich-runs.hwpx"
@@ -571,7 +571,7 @@ def test_table_set_column_widths_applies_weighted_cell_sizes() -> None:
571
571
  assert [table.cell(1, col_index).width for col_index in range(3)] == widths
572
572
 
573
573
 
574
- def test_builder_table_integrates_widths_shading_and_merges(tmp_path) -> None:
574
+ def test_builder_table_integrates_vertical_merge(tmp_path) -> None:
575
575
  from hwpx.builder import Document, Section, Table
576
576
 
577
577
  path = tmp_path / "builder-table-integrated.hwpx"
@@ -624,7 +624,7 @@ def test_table_set_column_widths_updates_cell_sizes(tmp_path) -> None:
624
624
  assert [reopened_table.cell(1, col).width for col in range(3)] == [7200, 10800, 3600]
625
625
 
626
626
 
627
- def test_builder_table_integrates_widths_shading_and_merges(tmp_path) -> None:
627
+ def test_builder_table_integrates_header_merge(tmp_path) -> None:
628
628
  from hwpx.builder import Document, Section, Table
629
629
 
630
630
  path = tmp_path / "builder-table-integrated.hwpx"
@@ -8,7 +8,6 @@ The real-Hancom verification is the opt-in oracle run, not these tests.
8
8
  """
9
9
  from __future__ import annotations
10
10
 
11
- import io
12
11
  import json
13
12
  from pathlib import Path
14
13
 
@@ -16,8 +15,6 @@ import pytest
16
15
 
17
16
  from hwpx import HwpxDocument
18
17
  from hwpx.conformance import (
19
- Badge,
20
- BadgeThresholds,
21
18
  CaseResult,
22
19
  ConformanceCase,
23
20
  ConformanceCorpus,
@@ -8,7 +8,6 @@ from __future__ import annotations
8
8
 
9
9
  from pathlib import Path
10
10
 
11
- import pytest
12
11
 
13
12
  from hwpx.tools.read_fidelity import corpus_fidelity
14
13
 
@@ -9,7 +9,6 @@ from typing import Any
9
9
 
10
10
  from lxml import etree
11
11
 
12
- from hwpx.document import HwpxDocument
13
12
  from hwpx.oxml import HwpxOxmlSection, parse_section_xml
14
13
  from hwpx.oxml import GenericElement
15
14
  from hwpx.oxml.body import (
@@ -194,12 +194,25 @@ def test_compose_returns_not_ok_when_open_safety_raises(tmp_path, monkeypatch):
194
194
  # --------------------------------------------------------------------------- #
195
195
  # Privacy: no residual source PII in committed templates or generated docs.
196
196
  # --------------------------------------------------------------------------- #
197
- _PII_NEEDLES = [
198
- "홍옥수", "csteacher", "bluewave", "shkimde", "옥지현", "keris", "kokyu",
199
- "광교", "매원", "경기도교육청", "학교공간혁신", "상용클라우드",
197
+ _PUBLIC_PRIVACY_SENTINELS = [
198
+ "source-author@example.invalid",
199
+ "private-origin-user",
200
+ "source-institution.example",
201
+ "source-location.example",
202
+ "source-project-code",
200
203
  ]
201
204
 
202
205
 
206
+ def _privacy_needles() -> list[str]:
207
+ """Return synthetic public sentinels plus an optional private-CI denylist."""
208
+ private = [
209
+ value.strip().lower()
210
+ for value in os.environ.get("HWPX_PRIVATE_PII_NEEDLES", "").split(",")
211
+ if value.strip()
212
+ ]
213
+ return _PUBLIC_PRIVACY_SENTINELS + private
214
+
215
+
203
216
  def _text_blob(data: bytes) -> str:
204
217
  import zipfile
205
218
 
@@ -213,13 +226,19 @@ def _text_blob(data: bytes) -> str:
213
226
 
214
227
  @pytest.mark.parametrize("pid", PROFILES)
215
228
  def test_profile_and_output_carry_no_source_pii(pid):
229
+ needles = _privacy_needles()
216
230
  prof = load_profile(pid)
217
231
  blob = _text_blob(prof.template_bytes)
218
- assert not [n for n in _PII_NEEDLES if n in blob], pid
232
+ assert not [n for n in needles if n in blob], pid
219
233
  data, res = compose_bytes(_plan(pid))
220
234
  assert res.ok
221
235
  out_blob = _text_blob(data)
222
- assert not [n for n in _PII_NEEDLES if n in out_blob], pid
236
+ assert not [n for n in needles if n in out_blob], pid
237
+
238
+
239
+ def test_private_ci_privacy_needles_are_supported(monkeypatch):
240
+ monkeypatch.setenv("HWPX_PRIVATE_PII_NEEDLES", "private-ci-sentinel,second-private-marker")
241
+ assert _privacy_needles()[-2:] == ["private-ci-sentinel", "second-private-marker"]
223
242
 
224
243
 
225
244
  # --------------------------------------------------------------------------- #
@@ -7,7 +7,7 @@ from hwpx import (
7
7
  create_document_from_plan,
8
8
  validate_document_plan,
9
9
  )
10
- from hwpx.builder import Bullet, Document, Heading, Paragraph, Run, Section, Table
10
+ from hwpx.builder import Bullet, Document, Heading, Paragraph, Run, Section
11
11
  from hwpx.document import HwpxDocument
12
12
 
13
13
  DOCUMENT_PLAN_V2_SCHEMA_VERSION = "hwpx.document_plan.v2"
@@ -8,7 +8,6 @@ from zipfile import ZipFile
8
8
  import pytest
9
9
  from lxml import etree
10
10
 
11
- import hwpx.document as document_module
12
11
  from hwpx.document import HwpxDocument
13
12
  from hwpx.opc.package import HwpxPackageError
14
13
  from hwpx.tools.package_validator import validate_editor_open_safety