Skip to main content

PyO3 Python bindings for rhwp — parser and renderer for HWP/HWPX documents (Korean word processor format)

Project description

rhwp-python

한국어 | English

PyPI Python CI License: MIT

⚠️ 비공식 커뮤니티 패키지입니다. 본 프로젝트는 edwardkim/rhwp공식 배포가 아니며, rhwp 메인테이너가 직접 PyPI 에 올릴 경우를 대비해 이름을 rhwp-python 으로 양보해 둔 상태입니다. rhwp 코어 버그는 업스트림 에 보고해 주세요.

rhwp — Rust 기반 HWP/HWPX(한컴오피스 문서) 파서·렌더러 — 의 PyO3 Python 바인딩.

  • PyPI 패키지명: rhwp-python
  • Python import: import rhwp
  • Rust 코어: edwardkim/rhwp

왜 rhwp-python 인가

  • HWP + HWPX 동시 지원 — 대표 대안인 pyhwp 는 HWP5 만 지원하고 2016년 이후 유지보수 중단 상태. rhwp 는 두 포맷을 같은 API 로 처리.
  • 텍스트 추출 62배 빠름 — HWP5 기준 pyhwp 대비 96 ms vs 5,980 ms (sandbox 벤치).
  • LangChain 즉시 연동rhwp.integrations.langchain.HwpLoader 를 extras 로 제공, RAG 파이프라인에 바로 플러그인 가능.
  • 타입 완비py.typed + .pyi 스텁, pyright clean.

요구 사항

  • Python 3.10+ (abi3-py310 wheel 하나로 3.10 ~ 3.13+ 커버)
  • 코어 API 는 런타임 Python 의존성 없음
  • rhwp-python[langchain] extras 는 langchain-core>=0.2 하나만 추가 설치

설치

pip install rhwp-python
# 또는
uv add rhwp-python

사용법

import rhwp

# HWP / HWPX 파싱 — 파일 I/O + 파싱 단계에서 GIL 해제
doc = rhwp.parse("report.hwp")
print(doc.section_count, doc.paragraph_count, doc.page_count)

# 텍스트
full_text: str = doc.extract_text()          # 빈 문단 제외, "\n" 으로 join
paragraphs: list[str] = doc.paragraphs()      # 빈 문단 포함 원본 리스트

# SVG 렌더링 — 단일 페이지 또는 전체
svg_page0: str = doc.render_svg(page=0)
all_svgs: list[str] = doc.render_all_svg()
written: list[str] = doc.export_svg("output/", prefix="page")
# → page_001.svg, page_002.svg, ... (단일 페이지면 page.svg)

# PDF 렌더링 — list[int] 가 아니라 Python `bytes` 반환
pdf: bytes = doc.render_pdf()
byte_size: int = doc.export_pdf("output.pdf")

rhwp.Document(path)rhwp.parse(path) 와 동일하게 동작.

페이지 PNG 렌더링 (VLM 입력)

VLM (Vision-Language Model — Claude / GPT-4V / Gemini Vision 등) 의 시각 입력 용도. 텍스트 표면 (SVG / Markdown / IR) 으로는 평탄화되는 표 셀 병합 / 수식의 공간 배치 / 그림 / 복잡 레이아웃의 시각 의미를 보존한다. 상류 rhwp v0.7.10 의 native-skia raster pipeline (PR #599) 위 thin wrapper — 별도 extras 없이 default wheel 에 통합 (skia binary 포함).

import rhwp

doc = rhwp.parse("report.hwp")

# 단일 페이지 — bytes (PNG magic 으로 시작)
png: bytes = doc.render_png(page=0)
png_2x: bytes = doc.render_png(page=0, scale=2.0)        # 픽셀 너비 약 2배

# 모든 페이지 일괄 (메모리 모델 — 페이지 100 × 약 500 KB ≈ 50 MB)
all_pngs: list[bytes] = doc.render_all_png()

# 디스크 export — page_001.png, page_002.png, ... (단일 페이지면 page.png)
written: list[str] = doc.export_png("output/", prefix="page")

# Async 변형 (파일 read 만 thread offload, render 는 호출 스레드)
import asyncio
png = asyncio.run(rhwp.arender_png("report.hwp", 0, scale=1.5))

Anthropic Vision API 호출 예 — Claude 가 페이지 시각 정보를 직접 해석:

import base64
import anthropic
import rhwp

png_bytes = rhwp.parse("report.hwp").render_png(page=0, scale=1.5)
client = anthropic.Anthropic()
message = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "image",
                "source": {
                    "type": "base64",
                    "media_type": "image/png",
                    "data": base64.b64encode(png_bytes).decode("ascii"),
                },
            },
            {"type": "text", "text": "이 페이지의 표 셀 병합 구조를 설명해."},
        ],
    }],
)
print(message.content[0].text)

max_pixels 는 DoS 방어용 픽셀 상한 (기본 8192 × 8192 = 67_108_864). 초과 시 ValueError("raster pixel count out of range: ..."). 사용자가 명시 override 가능 — 예: doc.render_png(0, max_pixels=200_000_000).

HWPX 저장 (writeback)

parse 한 문서를 다시 HWPX 파일로 저장하는 역방향 표면. Document IR 이 포맷 독립이라 HWP5 로 parse 한 문서도 HWPX 로 출력된다 (HWP5 → HWPX 포맷 변환). 직렬화는 상류 rhwpserialize_hwpx (PR #170) 에 위임한다.

import rhwp

doc = rhwp.parse("report.hwp")

# 메모리 bytes — ZIP magic 으로 시작 (첫 엔트리 STORED mimetype = application/hwp+zip)
data: bytes = doc.to_hwpx_bytes()

# 디스크 저장 — 작성 바이트 수 반환
written: int = doc.export_hwpx("out.hwpx")

# HWP5 → HWPX 변환도 동일 (입력 포맷 무관)
rhwp.parse("legacy.hwp").export_hwpx("converted.hwpx")

보존 범위 — 텍스트·문단은 round-trip 의미를 보존한다 (parse → 저장 → 재파싱 시 섹션 수 / 문단 수 / 문단 텍스트 동등). 표·그림·수식은 상류 serializer 의 현 보존 범위에 위임하며 의미 보존을 보장하지 않는다 (예외 없는 직렬화만 보장). 표·그림의 round-trip 의미 보존은 후속 버전 과제다. round-trip 은 의미적 동등성 기준이며 byte 단위 동일은 보장하지 않는다 (ZIP 압축 / canonical default 주입 등).

직렬화 실패 (참조 무결성 위반 — BinData 누락 등) 는 ValueError, 파일 쓰기 실패 (부모 디렉토리 부재 등) 는 OSError.

LangChain 통합

pip install "rhwp-python[langchain]"
from rhwp.integrations.langchain import HwpLoader

# 문서 전체를 단일 Document 로 (기본 — single 모드)
docs = HwpLoader("report.hwp").load()

# 빈 문단 제외, 문단 1개당 Document 1개 (RAG 청킹용 — paragraph 모드)
docs = HwpLoader("report.hwp", mode="paragraph").load()

# lazy_load: Document 를 on-the-fly 로 yield (paragraph 모드에서 O(1) peak memory)
for d in HwpLoader("report.hwp", mode="paragraph").lazy_load():
    index_into_vector_store(d)   # 사용자 파이프라인

# 표준 LangChain 텍스트 스플리터에 바로 연결
from langchain_text_splitters import RecursiveCharacterTextSplitter
chunks = RecursiveCharacterTextSplitter(chunk_size=500).split_documents(docs)

모든 Document 메타데이터: source, section_count, paragraph_count, page_count, rhwp_version. paragraph 모드에서는 paragraph_index 추가.

Document IR

RAG / LLM 파이프라인이 직접 소비하는 구조화 문서 모델. Pydantic V2 모델 + JSON Schema (Draft 2020-12) — HWP 의 구역 / 단락 / 표 / 그림 / 수식 / 각주 / 목록 / 캡션 / 목차 / 필드를 손실 없이 노출한다.

from rhwp.ir.nodes import ParagraphBlock, TableBlock

doc = rhwp.parse("report.hwp")
ir = doc.to_ir()                       # -> rhwp.ir.nodes.HwpDocument (Pydantic, frozen)
json_str = doc.to_ir_json(indent=2)    # JSON 직렬화

# 본문 블록을 순서대로 스트리밍 (표/문단 혼합, TableCell.blocks 까지 재귀)
for block in ir.iter_blocks(scope="body"):
    if isinstance(block, ParagraphBlock):
        print("P", block.prov.section_idx, block.prov.para_idx, block.text)
    elif isinstance(block, TableBlock):
        print("T", block.rows, "x", block.cols, "cells=", len(block.cells))

표 3중 표현cells (구조화 SQL/순회용) + html (HtmlRAG 호환 LLM 프롬프트) + text (평문 검색 폴백) 가 병기된다. 중첩 표는 TableCell.blocks 재귀로 자연 지원.

LangChain 통합 — 기존 loader 에 mode="ir-blocks" 추가:

from rhwp.integrations.langchain import HwpLoader

docs = HwpLoader("report.hwp", mode="ir-blocks").load()
# ^ 단락은 page_content=text, 표는 page_content=HTML. 메타에 kind / section_idx /
#   para_idx / (표의 경우) rows / cols / text / caption 포함

JSON Schemarhwp.ir.schema.export_schema() / load_schema(). 공개 $id: https://danmeon.github.io/rhwp-python/schema/hwp_ir/v1/schema.json (불변 경로).

View 변환 (v0.4.0+)HwpDocument.to_markdown() / to_html(include_css=False) 인스턴스 메서드로 IR 을 외부 view 포맷으로 직접 변환:

ir = rhwp.parse("report.hwp").to_ir()

md = ir.to_markdown()                 # GFM (표 / 각주 / 수식 / 이미지 placeholder)
html = ir.to_html(include_css=True)   # 완전 HTML5 문서, <head> 안 단일 <style> 동봉

표는 모든 셀 span == 1 일 때 GFM |...|, 병합 셀 (rowspan/colspan > 1) 은 TableBlock.html 그대로 inline. 각주/미주는 본문 paragraph 안 [^N] reference + 끝 정의 (Markdown) / <aside id="fn-N"> 정의 (HTML). 이미지는 picture.image.uri (bin://N) pass-through — raw bytes 가 필요하면 Document.bytes_for_image(picture) 를 별도 호출 (embedded 모드 미지원). 머리글/꼬리말은 출력 미포함 (페이지 단위 장식).

호출은 IR 인스턴스를 변경하지 않아 (frozen=True) 동일 IR 에 대한 재호출은 byte-equal.

rhwp-py CLI

pip install "rhwp-python[cli]"          # parse / version / schema / ir / blocks
pip install "rhwp-python[cli-chunks]"    # + chunks (langchain text splitter)

rhwp-py parse report.hwp
rhwp-py blocks report.hwp --kind table --format ndjson | jq '.rows'
rhwp-py chunks report.hwp --size 1000 --format ndjson

rhwp-py 는 구조 추출 (IR / 블록 / 청크 / 스키마) 전담 — 시각 출력 (SVG/PDF) / 메타데이터 덤프는 상류 rhwp Rust 바이너리. 자세한 사용은 rhwp-py --help 또는 cli.md 참조.

MCP server (rhwp-mcp)

Model Context Protocol 서버 — Claude Desktop / Cursor / Cline / Continue.dev / Goose 등 LLM 에이전트가 HWP/HWPX 파일을 직접 파싱·요약·청크화할 수 있다. standalone fastmcp v3 기반 (2026-05 기준 MCP 서버 약 70% 시장 점유의 사실상 표준).

pip install "rhwp-python[mcp]"           # 도구 6 종 (parse / extract / IR / blocks / view×2)
pip install "rhwp-python[mcp-chunks]"    # + chunks (RAG 청킹 — langchain-text-splitters)

노출 도구 (8 종)

도구 입력 출력
parse_hwp_summary path ParseSummary — sections / paragraphs / pages 카운트 + rhwp-core 버전
extract_text path str — 단락별 평문 (LF 결합)
get_ir path HwpDocument — Document IR 전체 (Pydantic 모델, fastmcp 자동 직렬화)
iter_blocks path, kind?, scope, limit? list[Block] — discriminated union (paragraph / table / picture / ... 11 변형, kind / scope 필터링)
to_markdown path str — GFM Markdown (v0.4.0 view API thin wrapper)
to_html path, include_css str — HTML5 문서 (v0.4.0 view API thin wrapper)
chunks path, mode, size, overlap, include_furniture list[ChunkRecord] — LangChain RecursiveCharacterTextSplitter 적용 청크. [mcp-chunks] extras 필요
render_page_png path, page, scale, max_pixels? ImageContent — base64 PNG + mimeType="image/png". VLM 시각 입력용 (v0.6.0+)

v0.5.1 마이그 노트 — 출력 시그니처가 dict / list[dict] 에서 Pydantic 모델로 강화됐습니다 (PATCH). fastmcp Client 의 result.structured_content (raw dict, MCP wire format) 는 v0.5.0 과 byte-equal — 외부 LLM 프롬프트 / 후처리 코드 영향 0. 다만 result.data 사용 패턴은 변경: v0.5.0 의 result.data["body"] (dict 인덱싱) → v0.5.1 의 result.data.body (typed attribute) 또는 result.data.model_dump()["body"]. iter_blocks 의 list element 는 fastmcp v3 의 oneOf deserialization 한계로 dict 폴백 — block["kind"] access 패턴은 그대로 동작.

Claude Desktop 등록

claude_desktop_config.json 에 추가:

{
  "mcpServers": {
    "rhwp": {
      "command": "rhwp-mcp"
    }
  }
}

(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json. Windows: %APPDATA%\Claude\claude_desktop_config.json.) Claude Desktop 재시작 후 도구 아이콘에 8 개 도구 노출.

다른 클라이언트

클라이언트 stdio streamable-http 등록 방법
Claude Desktop claude_desktop_config.json (위 예시)
Cline (VSCode) VSCode 설정 → MCP servers
Cursor Settings → Features → Model Context Protocol
Continue.dev ⚠️ (실험) ~/.continue/config.json
Goose (Block) goose configure
자체 에이전트 Anthropic SDK 의 MCP client / fastmcp Client

Streamable HTTP (서버 배포)

서버 컨테이너 / 다중 클라이언트 시나리오는 streamable-http transport:

rhwp-mcp --transport streamable-http --port 8000
# 외부 노출 (보안: reverse proxy + 인증 운영자 책임)
rhwp-mcp --transport streamable-http --host 0.0.0.0 --port 8000

기본 --host 127.0.0.1 — 외부 노출 회피. rhwp-mcp 는 인증 / TLS / sandboxing 미내장 — Caddy / Nginx 등 reverse proxy 가 책임. 자세한 사용은 rhwp-mcp --help 또는 mcp.md 참조.

성능

Apple M2 (8 코어) release 빌드. Parse = 파일 읽기 + 전체 파싱 + Document 생성. 워크로드: 9 개 파일 (aift.hwp 5.5 MB + table-vpos-01.hwpx 359 KB + tac-img-02.hwpx 3.96 MB, ×3).

워커 수 Parse 시간 순차 대비 가속
1 268 ms 1.00× (기준)
2 141 ms 1.91×
4 97 ms 2.76×
8 67 ms 4.01×

parse() 와 PDF 변환 단계는 py.detach 로 GIL 을 해제하므로 ThreadPoolExecutor 가 코어 수에 비례해 스케일. PDF 렌더링 자체는 usvg + pdf-writer 내부에서 CPU/allocator 바운드라 2 ~ 3 워커에서 약 1.1× 정도만 향상됨 — 재현은 benches/bench_gil.py 참고.

알려진 제약 / 운영 노트

운영상 제약 (Document 의 단일 스레드 모델, async 진입점, PDF stdout 노이즈) 및 미구현 영역 요약은 KNOWN_ISSUES.md. 작업 중 / 계획 항목은 docs/roadmap/ 의 활성 spec 인덱스.

개발

소스에서 빌드·테스트·기여하는 절차는 CONTRIBUTING.md 참조.

버전 관리

이 Python 패키지와 rhwp Rust 코어는 독립적으로 버저닝됩니다. rhwp.version() 은 이 패키지 버전을, rhwp.rhwp_core_version() 은 번들된 Rust 코어 버전을 반환합니다.

라이선스

MIT. 저작권자: Edward Kim (rhwp Rust 코어) + DanMeon (rhwp-python 바인딩). 자세한 내용은 LICENSE.

프로젝트 홈

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rhwp_python-0.7.0.tar.gz (10.3 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rhwp_python-0.7.0-cp310-abi3-win_amd64.whl (6.6 MB view details)

Uploaded CPython 3.10+Windows x86-64

rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.9 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

rhwp_python-0.7.0-cp310-abi3-macosx_11_0_arm64.whl (5.6 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

rhwp_python-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl (5.9 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file rhwp_python-0.7.0.tar.gz.

File metadata

  • Download URL: rhwp_python-0.7.0.tar.gz
  • Upload date:
  • Size: 10.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rhwp_python-0.7.0.tar.gz
Algorithm Hash digest
SHA256 e0841a2a79c6ad1d21c6a639f449565c3e7757ac154d3d26d1b2afe3cb8843b2
MD5 d08a45a0b51890069de72916ccc5e2a7
BLAKE2b-256 a524c3889fd383832f55685955fd0dd5f2e5998e6e498ad8860054f71bd27f63

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0.tar.gz:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rhwp_python-0.7.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: rhwp_python-0.7.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 6.6 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rhwp_python-0.7.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c5f47db10135f1252393d0dad476178bd88af0a5379a09b75a8aef60b1f2bf3b
MD5 ffb6f0c1f3c7384c9dd1b05737c80248
BLAKE2b-256 7dde581658ff9795c0bff24dd25fdc09102c05b927794db69ad873885b55ab8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0-cp310-abi3-win_amd64.whl:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d9109dc9983ed9aaab79509b6fd5f33671dffe3b2bac5b29efe0454ad0822396
MD5 3d8ccb9057b0df5221143913cd4e0b93
BLAKE2b-256 bf7ca5752639053ffe74932cca6f8818ce1161cbe1e0225a158feed38d247a4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6471a31f52edd29e4877bb7c6fae55e18c24353c625c3a72fd713663046373aa
MD5 971bdd30e71ec7d8e977bd6f03ee9d39
BLAKE2b-256 7a43d0b509885bb212f5a4f27f050e046961ff7d893bf4bd5fc7258f7e5e5e75

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rhwp_python-0.7.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rhwp_python-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 241a131c55710588bc85027354ec1467c36a284815490c2f26f17c3183b360ea
MD5 7336bb20ee27b7c95070e561c5c12786
BLAKE2b-256 b35a238a911c81170a2c8d64fbf3b59e8932aa61d6711067d527631eb3f52191

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rhwp_python-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for rhwp_python-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 51b4bc4e4c7bbd2175864f0c46f28e0af96914dca1749f0cb7787a95c8bc57d8
MD5 3aa263191a5f921dc10dc9dabb8f3c4b
BLAKE2b-256 40c737904dc9da74486a0e582bf4d306eba67cd2736dedbe02a27f8729fc8bbe

See more details on using hashes here.

Provenance

The following attestation bundles were made for rhwp_python-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yml on DanMeon/rhwp-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page