Skip to main content

hwpforge

Tongs — Read, edit and generate Korean HWP/HWPX documents from Python.

본 제품은 한컴의 HWP 문서 파일(.hwp) 공개 문서를 참고하여 개발하였습니다. (Developed with reference to Hancom's public HWP file format documents: https://www.hancom.com/etc/hwpDownload.do.)

hwpforge wraps the HwpForge Rust library: a document model for the HWPX (OWPML) format, an HWP5 reader, a Markdown bridge and a PDF renderer. The Python package is a thin layer over that library, so it performs the same operations, with the same meaning, as the command line tool and the MCP server. What each frontend calls them differs: method names, argument spellings and some failure codes are Python's own public contract, and the other two keep theirs.

What it reads and writes

Reads .hwpx, and .hwp (HWP5) through hwpforge.convert_hwp5. That conversion is one way: the result is an HWPX document, and the original .hwp is never written back.

Writes .hwpx only. There is no .hwp output, and Hancom Office opens .hwpx natively. Documents also export to Markdown, JSON and PDF. A PDF needs the document's own fonts present on the host and named through font_dirs or discovery: by default a face that cannot be resolved fails the render rather than being guessed at. to_pdf(degraded=True) relaxes that and renders the missing face with a fallback, which changes how the page looks.

Rendering replays a layout stored in the document, so to_pdf needs a document that carries one. Two do: an HWPX Hancom saved, and an HWPX converted from HWP5, which carries the layout across by default — hwpforge.convert_hwp5(data).document.to_pdf(...). A document this library generated from Markdown or JSON carries no layout and is refused with PDF_RENDER_FAILED.

A paragraph whose line starts cannot be carried over exactly loses its layout and is reported as LAYOUT_CACHE_DROPPED; convert_hwp5(data, carry_layout_cache=False) leaves the layout out.

Install

pip install hwpforge

With uv: uv add hwpforge in a project, or uv pip install hwpforge in an environment.

Pin with ~= rather than ==. A Python-only fix ships as X.Y.Z.N, and an exact pin never receives it.

What is published

Artifact Platform Needs
cp39-abi3-manylinux_2_28_x86_64 Linux x86_64 glibc 2.28 or newer
cp39-abi3-manylinux_2_28_aarch64 Linux aarch64 glibc 2.28 or newer
cp39-abi3-macosx_11_0_arm64 macOS arm64 macOS 11 or newer
cp39-abi3-macosx_10_12_x86_64 macOS x86_64 macOS 10.12 or newer
cp39-abi3-win_amd64 Windows x64 —
hwpforge-<version>.tar.gz source distribution Rust 1.92 and maturin

One abi3 wheel per platform covers CPython 3.9 and newer. Free-threaded builds are not supported, because the stable ABI does not cover them.

Hosts without an index

The wheel is a zip file and the package declares no runtime dependencies, so it can be unpacked and imported without pip. The requirement is glibc 2.28 or newer, not a particular distribution — on any Linux x86_64 host with CPython 3.9+ (Debian 10/11/12, Ubuntu 20.04 and later; the file name below is the x86_64 wheel):

python3 -c "import zipfile; zipfile.ZipFile('hwpforge-<version>-cp39-abi3-manylinux_2_28_x86_64.whl').extractall('/opt/hf')"
PYTHONPATH=/opt/hf python3 -c "import hwpforge; print(hwpforge.__version__)"

GitHub Releases are immutable once published, so wheels are never attached there after the fact. Every wheel and the source distribution instead live on PyPI's files page, with the same bytes and sha256 that pip sees, so an air-gapped host can download a file straight from that page and unpack it the same way as above. A Python-only fix, versioned X.Y.Z.N, is published to PyPI alone and has no Release of its own.

Example

import hwpforge

doc = hwpforge.Document.open("proposal.hwpx")
print(doc.outline()["outline"]["title"])
doc = doc.fill({"applicant": "홍길동", "date": "2026-09-17"}).document
doc.save("proposal-filled.hwpx")

Document is immutable. Every editing method returns a new document in a result object alongside the operation's report, and leaves the receiver unchanged, so the re-assignment above is not optional.

Operations

A failure raises HwpForgeError, whose code is the stable string to branch on. The codes below are the ones each operation raises for its own characteristic failure; any operation that has to decode the document first can also raise DECODE_FAILED.

Document methods

Method Returns Characteristic failures
inspect(*, styles=False) InspectReport DECODE_FAILED
outline() OutlineReport DECODE_FAILED
fields() FieldsReport DECODE_FAILED
validate() ValidateReport DECODE_FAILED (an invalid document reports, not raises)
read(*, section, paras, table, field) ReadReport READ_TARGET_REQUIRED, READ_PARAS_INVALID, READ_PARA_RANGE_INVALID, READ_TABLE_OUT_OF_RANGE
diff(revised) DiffReport DECODE_FAILED
stamp_plan() StampPlanReport DECODE_FAILED
to_json(*, styles=True) TextResult[ToJsonReport] DECODE_FAILED
export_section(*, section, styles=True) TextResult[ExportSectionReport] SECTION_OUT_OF_RANGE
to_md(*, mode="styled") TextResult[ToMdReport] ENCODE_FAILED (mode="lossless": see the note below)
to_pdf(*, font_dirs, discovery, degraded, partial_cache_reject) BytesResult[ToPdfReport] PDF_RENDER_FAILED
fill(values) DocumentResult[FillReport] FIELD_NOT_FOUND, FIELD_NOT_FILLABLE, EMPTY_FIELD_VALUE
set_cell(*, table, at, right_of, below, text, specs) DocumentResult[SetCellReport] TABLE_NOT_FOUND, CELL_NOT_FOUND, INPUT_ENTRIES_NOT_CARRIED
patch(*, section, patch) DocumentResult[PatchReport] JSON_PARSE_FAILED, PATCH_FAILED
insert_para(*, section, anchor, text, before=False) DocumentResult[StructuralReport] PARAGRAPH_OUT_OF_RANGE, INPUT_ENTRIES_NOT_CARRIED
delete_para(*, section, indexes) DocumentResult[StructuralReport] PARAGRAPH_OUT_OF_RANGE, INPUT_ENTRIES_NOT_CARRIED
stamp(request, *, manifest=True) DocumentResult[StampReport] INPUT_ENTRIES_NOT_CARRIED, ENCODE_SEMANTIC_LOSS
restyle(*, preset) DocumentResult[RestyleReport] PRESET_NOT_FOUND, ENCODE_SEMANTIC_LOSS

to_md(mode="lossless") keeps what the preservation scope lists, raises ENCODE_FAILED for an object the scope lists as refused, and may leave out anything else (paragraph styles, headers and footers …) without an error — the scope is the "Lossless 보존 범위" section of the Markdown bridge guide.

Constructors and accessors beside these: Document.open(path) (bounded at 100 MB, raising INPUT_TOO_LARGE beyond it), Document.from_bytes(data) (no bound — the caller already holds the bytes), to_bytes(), save(path), and len() / == / hash() over the bytes.

set_cell, insert_para, delete_para and stamp re-encode the whole package, so they refuse a document Hancom saved with INPUT_ENTRIES_NOT_CARRIED or INPUT_NOT_ROUNDTRIP_SAFE rather than drop the entries it carries. fill and patch work on such a document.

Module functions

Function Returns Characteristic failures
convert_md(text, *, preset="default", base_dir=None) DocumentResult[ConvertMdReport] PRESET_NOT_FOUND
from_json(text, *, base=None) DocumentResult[EncodeReport] JSON_PARSE_FAILED
convert_hwp5(data, *, carry_layout_cache=True) DocumentResult[ConvertHwp5Report] HWP5_DECODE_FAILED
templates() TemplatesReport —
schema(*, kind="document") SchemaReport —

Every report but templates() and schema() carries a warnings key, which is always present and worth reading before saving the result.

Documentation

License

MIT OR Apache-2.0.

Metadata

Release files for hwpforge 0.17.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hwpforge 0.17.0
File Size Uploaded Provenance
hwpforge-0.17.0.tar.gz 4.0 MB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for hwpforge 0.17.0
File
hwpforge-0.17.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
hwpforge-0.17.0-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
hwpforge-0.17.0-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
hwpforge-0.17.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
hwpforge-0.17.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 37.8 MB

Release files / hwpforge-0.17.0.tar.gz

Download URL hwpforge-0.17.0.tar.gz
Size 4.0 MB
Tags Source
SHA-256 checksum
How to use checksums
648249c6ec20b53dd3f9d080f846a8ab805f1b6bffa96acb36031da0db593d4f
BLAKE2b-256 checksum
How to use checksums
7ab8b3ed5f887e91987bbf41b853d10b17709f5322b89db4707910e874ae667d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / hwpforge-0.17.0-cp39-abi3-win_amd64.whl

Download URL hwpforge-0.17.0-cp39-abi3-win_amd64.whl
Size 7.3 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
84d0f44c60f4203453072ab1dbb86f8c3c379fcc57ad5834faeae88fbd7ca8e8
BLAKE2b-256 checksum
How to use checksums
0db5651c2be430c4baf12104e8c0463154b25b5c5003f62ce8f7553be2d0c7be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / hwpforge-0.17.0-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL hwpforge-0.17.0-cp39-abi3-manylinux_2_28_x86_64.whl
Size 7.0 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
23e38285adb3420e34107711e7dd8590ae9176423643ffceded3b970f2fd8670
BLAKE2b-256 checksum
How to use checksums
6516a72db1b6a5634e5bdae1db2cd41c5aeae23d57491267a8ec8a6f83486dd9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / hwpforge-0.17.0-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL hwpforge-0.17.0-cp39-abi3-manylinux_2_28_aarch64.whl
Size 6.5 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
a223f17f3c53cc7e9bcbcd82e53d250243a4fdd7c69469deecf07433a9e4b4c6
BLAKE2b-256 checksum
How to use checksums
844cebd3cf6f13045475080683ea54e5034885fcfcda1892b8395940ce599d88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / hwpforge-0.17.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL hwpforge-0.17.0-cp39-abi3-macosx_11_0_arm64.whl
Size 6.3 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
64b700cf72f34917e9b548ac81c931f288de388f9adccee71a08fdccc2ca9a0c
BLAKE2b-256 checksum
How to use checksums
f0cb8f4f2b1d1b18daf156e5eac03bf1cb8c42b300e9f40445099874879744e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / hwpforge-0.17.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL hwpforge-0.17.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 6.7 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
3d00f59be3f5ad29ddb61dfb9bc57bafb6caaa515660fa28fad21f2b255d4881
BLAKE2b-256 checksum
How to use checksums
e956014604553341ef025b81877c4b8a22aef37a3dd700004125f53989cfb5ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for hwpforge 0.17.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page