Round-trip safe HWPX reader/editor/writer for Python
Project description
jakal-hwpx
파이썬에서 HWPX와 HWP 문서를 읽고, 수정하고, 검증하고, 변환하는 라이브러리입니다.
이 프로젝트는 한컴 GUI를 그대로 흉내 내는 편집기가 아닙니다. 대신 코드로 문서를 만들고, 구조화된 내용을 바꾸고, 저장 전후를 검증하는 데 초점을 둡니다. 템플릿 생성, 대량 치환, 표/필드/머리말/꼬리말 수정 같은 자동화 작업에 잘 맞습니다.
목차
설치
요구 사항:
- Python 3.11 이상
- Git LFS 불필요
PyPI에서 설치:
python -m pip install --upgrade pip
python -m pip install jakal-hwpx
로컬 체크아웃에서 설치:
python -m pip install --upgrade pip
python -m pip install .
개발 의존성까지 설치:
python -m pip install -e .[dev]
패키지 이름은 jakal-hwpx, import 경로는 jakal_hwpx입니다.
빠른 시작
새 문서를 만들고 HWPX와 HWP 둘 다 저장하려면 HancomDocument가 가장 단순합니다.
from jakal_hwpx import HancomDocument
doc = HancomDocument.blank()
doc.metadata.title = "분기 보고서"
doc.append_header("사내 배포용")
doc.append_paragraph("매출 요약")
doc.append_table(rows=2, cols=2, cell_texts=[["Q1", "Q2"], ["120", "135"]])
doc.append_equation("x+y", width=3200, height=1800)
doc.write_to_hwpx("build/report.hwpx")
doc.write_to_hwp("build/report.hwp")
HWPX만 직접 만질 거라면 HwpxDocument가 가장 짧습니다.
from jakal_hwpx import HwpxDocument
doc = HwpxDocument.blank()
doc.set_metadata(title="Hello")
doc.append_paragraph("Hello HWPX")
doc.save("build/hello.hwpx")
기존 HWP를 바로 수정하려면 HwpDocument를 쓰면 됩니다.
from jakal_hwpx import HwpDocument
doc = HwpDocument.open("input.hwp")
doc.append_paragraph("추가 문단")
doc.append_hyperlink("https://example.com", text="Example")
doc.strict_validate()
doc.save("build/edited.hwp")
이 라이브러리로 할 수 있는 일
- HWPX 문서를 직접 열고 수정하고 저장
- HWP 문서를 순수 Python으로 열고 수정하고 저장
- HWP와 HWPX를
HancomDocument기준으로 오가며 같은 편집 모델로 다루기 - 문단, 스타일, 표, 그림, 필드, 각주/미주, 머리말/꼬리말, 섹션 설정 같은 구조화된 요소 수정
- 저장 전후에 엄격 검증과 왕복 테스트로 결과 확인
- 필요하면 저수준 API로 내려가 HWP binary record를 직접 조사
이 라이브러리는 특히 이런 작업에 잘 맞습니다.
- 문서 템플릿 생성
- 필드 채우기
- 대량 텍스트 치환
- 표/도형/그림 데이터 갱신
- 문서 포맷 변환 자동화
- 저장 후 깨지지 않는지 확인하는 배치 처리
어떤 객체를 쓰면 되는가
처음 고를 때는 아래 표만 보면 됩니다.
| 객체 | 언제 쓰면 좋은가 | 설명 |
|---|---|---|
HancomDocument |
HWP와 HWPX를 같은 코드로 다루고 싶을 때 | 가장 권장되는 공통 편집 모델 |
HwpxDocument |
입력과 출력이 둘 다 HWPX일 때 | 가장 넓은 직접 편집 범위 |
HwpDocument |
기존 HWP를 직접 수정하거나 HWP로 저장할 때 | HWP 전용 객체 API |
HwpHwpxBridge |
HWP/HWPX 사이를 오가며 한쪽 결과물을 재료로 다른 쪽을 만들 때 | 문서 전환을 묶는 도우미 객체 |
HwpBinaryDocument |
binary record, stream, docinfo를 직접 봐야 할 때 | 가장 저수준 API |
짧게 말하면:
- 처음 시작:
HancomDocument - HWPX만 편집:
HwpxDocument - HWP 직접 편집:
HwpDocument - reverse engineering이나 디버깅:
HwpBinaryDocument
지원 범위
이 README의 지원 표는 "느낌"이 아니라 아래 기준으로 판정합니다.
직접 수정·재오픈: 공개 API로 생성 또는 수정한 뒤 저장하고, 다시 열어서 같은 의미로 복원되는 자동 테스트가 있습니다.왕복 보존:HWP -> HWPX,HWPX -> HWP, 또는A -> HancomDocument -> B경로에서 의미가 유지되는 자동 테스트가 있습니다.strict lint: 저장 전 구조 검사를 하는strict_lint_errors()또는strict_validate()가 연결돼 있습니다.metadata-backed: target 포맷에 native 자리가 없어 라이브러리 metadata나 carrier를 함께 써서 의미를 보존합니다. 현재memo/comment의author/memo_id/anchor_id/order/visible와form.placeholder가 대표적인 예시입니다. memo carrier는Textparameter를 pairing key로 저장하고, 없으면 기존 순서 기반으로 병합합니다.정규화: richer source를 target 포맷 제약에 맞게 일부 normalize해서 저장합니다.
표에 있는 항목만 "지원 약속"으로 봐야 합니다. 표에 없는 항목은 읽히더라도 공개 API나 안정성 계약의 일부로 보지 않는 편이 안전합니다.
문서 흐름별 판정 기준
| 흐름 | 판정 | 최소 기준 | 대표 테스트/근거 |
|---|---|---|---|
HWPX -> HWPX |
검증됨 | 직접 수정·재오픈 + strict lint | tests/test_document_model.py, tests/test_extended_features.py |
HWP -> HWP |
검증됨 | 직접 수정·재오픈 + strict lint + binary/reencode 회귀 | tests/test_hwp_binary.py, tests/test_hwp_document.py, scripts/audit_hwp_lossless_roundtrip.py |
HWP -> HWPX |
검증됨 | HWP를 읽어 HWPX로 재생성하고 block/control 의미 보존 확인 | tests/test_hancom_document.py, tests/test_bridge.py |
HWPX -> HWP |
검증됨, 단 정규화 있음 | HWPX를 읽어 HWP로 재생성하고 reopen/bridge roundtrip 확인 | tests/test_hancom_document.py, tests/test_bridge.py |
대표 회귀 명령은 아래와 같습니다. 통과 개수는 테스트 추가나 환경에 따라 변하므로, 지원 표의 근거는 숫자보다 "어떤 명령과 어떤 파일이 어떤 경로를 검증하는가"를 기준으로 읽는 편이 안전합니다.
python -m pytest tests/test_document_model.py tests/test_extended_features.py tests/test_hwp_binary.py tests/test_hwp_document.py tests/test_hancom_document.py tests/test_bridge.py tests/test_hancom_interop.py -q
컨트롤 패밀리별 지원 범위
아래 표도 같은 기준을 씁니다. 직접 수정·재오픈은 해당 포맷을 직접 편집하는 public API가 있다는 뜻이고, 왕복 보존은 교차 포맷 변환에서 의미가 유지된다는 뜻입니다.
| 항목 | HWPX -> HWPX |
HWP -> HWP |
HWP -> HWPX |
HWPX -> HWP |
비고 |
|---|---|---|---|---|---|
| 문단, 텍스트, 스타일 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | 가장 넓게 테스트된 축 |
| 머리말, 꼬리말 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | apply_page_type 포함 |
| 필드, 북마크, 하이퍼링크 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | HWP native field subtype 보존 |
| 각주, 미주, 자동번호, 페이지번호 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | setter와 bridge parity 있음 |
| 섹션 설정, page border fill, visibility | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | strict lint와 section-level 회귀 포함 |
| 표 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(정규화) | cell, margin, spacing, border fill, span 계열 포함 |
| 그림 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(일부 정규화) | crop, line style, layout, 일부 native probe 반영 |
도형, connectLine |
직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(일부 정규화) | subtype wrapper와 주요 setter 포함 |
| 수식 | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(일부 정규화) | layout/outMargins/rotation surface 포함 |
| OLE | 직접 수정·재오픈 | 직접 수정·재오픈 | 왕복 보존 | 왕복 보존(일부 정규화) | extent, line style, metadata 포함 |
| 차트 | 직접 수정·재오픈 | 직접 수정·재오픈(metadata-backed) |
왕복 보존 | 왕복 보존(metadata-backed) |
HWPX는 native chart schema, HWP는 semantic metadata layer 사용 |
| form object | 직접 수정·재오픈 | 직접 수정·재오픈(metadata-backed) |
왕복 보존 | 왕복 보존(metadata-backed) |
HWPX는 native form tag를 사용합니다. label/items/value/checked/locked는 native 쪽에 있고, placeholder는 Hancom native HWPX probe에서 전용 slot이 확인되지 않아 JAKAL_FORM_META carrier를 씁니다. HWP는 semantic metadata layer 사용 |
| memo/comment | 직접 수정·재오픈 | 직접 수정·재오픈(텍스트 native, 추가 metadata는 metadata-backed) |
왕복 보존(native + carrier 혼합) | 왕복 보존(native + metadata-backed) |
HWPX 텍스트는 native hiddenComment, 추가 metadata는 JAKAL_MEMO carrier 사용. carrier는 Text parameter로 native memo와 먼저 matching하고, 없을 때만 순서로 병합합니다. Hancom native HWPX/HWPML probe에서 전용 slot이 아직 확인되지 않음 |
안정성에 대해
이 프로젝트는 한컴 GUI보다 "자동화 자유도" 쪽이 강합니다. 사용자가 화면에서 임의 위치를 마우스로 편집하는 범용 GUI 편집기 역할보다는, 코드로 반복 작업을 처리하고 저장 후 안정성을 검증하는 데 더 잘 맞습니다.
무변경 HWP -> HWP 재인코드 쪽은 lossless audit이 붙어 있고, 최근 기준으로 corpus 64건이 byte-identical입니다. 지원된 control 계열은 save/reopen 회귀와 교차 포맷 roundtrip 테스트를 같이 유지합니다.
주요 API
HancomDocument
가장 권장되는 공통 편집 모델입니다.
주요 메서드:
HancomDocument.blank()HancomDocument.read_hwpx(path)HancomDocument.read_hwp(path)append_paragraph()append_table(),append_picture(),append_shape(),append_equation(),append_ole()append_field(),append_hyperlink(),append_bookmark(),append_note()append_header(),append_footer()write_to_hwpx(path)write_to_hwp(path)
HwpxDocument
HWPX를 직접 편집할 때 쓰는 주력 객체입니다.
주요 메서드:
HwpxDocument.open(path)HwpxDocument.blank()append_paragraph()append_header(),append_footer()append_table(),append_picture(),append_shape(),append_equation(),append_ole()append_field(),append_hyperlink(),append_bookmark(),append_note()section_settings()strict_lint_errors(),strict_validate()save(path)
HwpDocument
HWP 편집에 쓰는 주력 객체입니다.
주요 메서드:
HwpDocument.open(path)HwpDocument.blank()append_paragraph()append_table(),append_picture(),append_shape(),append_equation(),append_ole()append_field(),append_hyperlink(),append_bookmark(),append_note()append_header(),append_footer(),append_auto_number()tables(),pictures(),fields(),notes(),section(index)strict_lint_errors(),strict_validate()save(path)
HwpHwpxBridge
이미 가진 문서를 기준으로 HWP/HWPX/HancomDocument를 오가며 저장할 때 편리한 도우미 객체입니다.
주요 메서드:
HwpHwpxBridge.open(path)HwpHwpxBridge.from_hwp(source)HwpHwpxBridge.from_hwpx(source)hancom_document()hwp_document()hwpx_document()save_hwp(path)save_hwpx(path)save(path)
HwpBinaryDocument
가장 저수준의 HWP API입니다.
다음 상황에서 씁니다.
- binary stream을 직접 보고 싶을 때
DocInfoModel,SectionModel을 다뤄야 할 때- reencode나 probe 작업을 할 때
- 지원 매핑을 더 넓히기 위해 record tree를 조사할 때
예제
HWPX 열고 수정 후 저장
from jakal_hwpx import HwpxDocument
doc = HwpxDocument.open("input.hwpx")
doc.replace_text("초안", "최종")
doc.append_paragraph("승인 완료")
doc.strict_validate()
doc.save("build/edited.hwpx")
HWP 열고 수정 후 저장
from jakal_hwpx import HwpDocument
doc = HwpDocument.open("input.hwp")
doc.append_paragraph("추가 문단")
doc.append_hyperlink("https://example.com", text="Example")
doc.strict_validate()
doc.save("build/edited.hwp")
HWP를 HWPX로 변환
from jakal_hwpx import HancomDocument
doc = HancomDocument.read_hwp("input.hwp")
doc.write_to_hwpx("build/exported.hwpx")
HWPX를 HWP로 변환
from jakal_hwpx import HancomDocument
doc = HancomDocument.read_hwpx("input.hwpx")
doc.write_to_hwp("build/exported.hwp")
bridge 도우미로 포맷 전환
from jakal_hwpx import HwpHwpxBridge
bridge = HwpHwpxBridge.open("input.hwp")
bridge.save_hwpx("build/bridge.hwpx")
bridge.save_hwp("build/bridge-copy.hwp")
HWP record 살펴보기
from jakal_hwpx import HwpBinaryDocument
doc = HwpBinaryDocument.open("input.hwp")
print(doc.file_header().version)
print(doc.docinfo_model().id_mappings_record().named_counts())
print(doc.section_model(0).controls())
검증과 테스트
핵심 회귀 세트:
python -m pip install -e .[dev]
python -m pytest tests/test_document_model.py tests/test_extended_features.py tests/test_hwp_binary.py tests/test_hwp_document.py tests/test_hancom_document.py tests/test_bridge.py tests/test_hancom_interop.py -q
각 파일은 대략 아래 범위를 봅니다.
tests/test_document_model.py: HWPX 직접 authoring, native HWPX schema, strict linttests/test_extended_features.py: HWPX 고급 기능과 batch edit surfacetests/test_hwp_binary.py: HWP reencode, docinfo, section model, binary payload 안정성tests/test_hwp_document.py: HWP 공개 wrapper/setter, strict lint, save/reopen 회귀tests/test_hancom_document.py:HWP <-> HancomDocument <-> HWPXbridge paritytests/test_bridge.py: explicit bridge helper와HwpHwpxBridge공개 API 회귀tests/test_hancom_interop.py: Hancom smoke/security script contract
release gate와 안정성 검사:
python scripts/check_release.py
HWP lossless audit:
python scripts/audit_hwp_lossless_roundtrip.py
선택적 Hancom smoke validation:
powershell -ExecutionPolicy Bypass -File scripts/setup_hancom_security_module.ps1 -DownloadIfMissing
powershell -ExecutionPolicy Bypass -File scripts/run_hancom_smoke_validation.ps1 -InputPath examples\samples\hwpx\AI와_특이점_보고서.hwpx -OutputPath .codex-temp\hancom-smoke\sample.roundtrip.hwpx
powershell -ExecutionPolicy Bypass -File scripts/run_hancom_corpus_smoke_validation.ps1
일반적인 사용에선 pure Python 경로가 기본입니다. Hancom 쪽은 "정말 한컴에서 열어도 괜찮은지"를 추가로 확인할 때 쓰면 됩니다.
추가 문서
- HWPX_MODULE.md: 어떤 객체를 언제 써야 하는지 정리한 모듈 선택 가이드
- STABILITY_CONTRACT.md: 지원 범위와 release gate 기준
- scripts/check_release.py: release gate 스크립트
- scripts/audit_hwp_lossless_roundtrip.py: HWP lossless reencode audit
- scripts/run_bridge_stability_lab.py: HWP/HWPX bridge stability matrix
- examples/SHOWCASE.md: 생성 예시 모음
- RELEASING.md: 배포 절차
- THIRD_PARTY_NOTICES.md: 샘플 문서와 재배포 관련 고지
고급 도구도 루트 import에서 바로 쓸 수 있습니다.
build_hwp_pure_profile()append_feature_from_profile()run_template_lab()hwp_collectiondonor scanning 도구
이 도구들은 corpus 분석이나 template-backed HWP 작업에 유용하지만, 일반적인 앱 코드의 기본 진입점은 아닙니다.
라이선스
프로젝트 소스 코드는 MIT 라이선스를 따릅니다.
샘플 문서와 생성 결과물은 별도 권리를 가질 수 있습니다. 재배포 전에는 THIRD_PARTY_NOTICES.md를 확인하세요.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jakal_hwpx-0.3.0b3.tar.gz.
File metadata
- Download URL: jakal_hwpx-0.3.0b3.tar.gz
- Upload date:
- Size: 2.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4425b2368f79dfdbd16acfcded4602ec51c893ac752db904bd80a1e4481ce9e
|
|
| MD5 |
06e50ed863e52987691f1468e325f07a
|
|
| BLAKE2b-256 |
261852b8263cb71bf856bb01f48d3aadc467a24060d6a136523b2213c92083ed
|
File details
Details for the file jakal_hwpx-0.3.0b3-py3-none-any.whl.
File metadata
- Download URL: jakal_hwpx-0.3.0b3-py3-none-any.whl
- Upload date:
- Size: 2.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
121f06167d737747a3a229a9e2d81292005442a04373118dacb5b2413aca8b28
|
|
| MD5 |
7c891b6e169e31de72a73b1308e68893
|
|
| BLAKE2b-256 |
2660d352b20ac08b3447a64c4de85c0a234374b2078d03ccc67028172ac188a8
|