Skip to main content

kordoc Python SDK

Python 에서 kordoc 으로 한국 문서(HWP·HWPX·PDF·DOCX·XLSX·PPTX …)를 파싱합니다. 상주 kordoc 엔진 워커(kordoc parse-worker --protocol 2)를 띄워 재사용하므로 문서마다 Node 를 새로 실행하지 않습니다. 파싱은 엔진 한 곳에서 하며 결과는 Node parse() 와 같습니다.

설치

이 패키지는 엔진을 설치하지 않습니다. 실행 환경에 Node.js(20 이상)와 kordoc 엔진이 따로 있어야 합니다.

npm i -g kordoc        # 엔진 (PATH 에 kordoc)
pip install -U "kordoc>=0.2.0"  # SDK (Python 3.11 이상, 외부 의존성 없음)

엔진 위치는 KordocConfig(node=..., cli=...), 환경변수 KORDOC_NODE·KORDOC_CLI, PATH 의 node·kordoc 순으로 찾습니다. cli 에는 엔진의 dist/cli.js(또는 npm 이 만든 kordoc 링크)를 줍니다. 실행 인자는 배열로 넘기며 shell·npx 를 쓰지 않습니다. Windows 의 kordoc.cmd·pnpm 셸 shim 처럼 node 로 실행할 수 없는 래퍼를 찾으면 옆의 node_modules/kordoc/dist/cli.js 로 바꿔 쓰고, 그것도 없으면 dist/cli.js 를 지정하라는 오류를 냅니다. 지정한 경로에 파일이 없으면 워커를 띄우기 전에 KordocStartError 를 냅니다.

폐쇄망에서는 오프라인 번들을 풀고 그 안의 엔진을 가리키면 됩니다.

from kordoc import KordocClient, KordocConfig

config = KordocConfig(
    node="/opt/node/bin/node",
    cli="/opt/kordoc-offline/node_modules/kordoc/dist/cli.js",
    env={"KORDOC_OFFLINE": "1"},
)

사용

from kordoc import KordocClient

with KordocClient() as client:
    result = client.parse("문서.hwpx", table_format="gfm")   # 중첩 표를 부모·자식 트리로 편 GFM
    if result.success:
        print(result.markdown)
    else:
        print(result.code, result.error)                      # 문서를 읽지 못한 것은 예외가 아니다
import asyncio
from kordoc import AsyncKordocClient

async def main() -> None:
    async with AsyncKordocClient(max_workers=2) as client:
        results = await asyncio.gather(*(client.parse(p) for p in ["a.hwp", "b.pdf"]))

asyncio.run(main())
  • parse(path, **options) · parse_bytes(data, **options) · warmup(path, **options) · close()(aclose())
  • with / async with 를 나가면 소유 워커를 모두 종료·회수합니다. 패키지 import·클라이언트 생성만으로는 프로세스를 띄우지 않습니다.
  • result.raw 는 엔진 결과 JSON 원본입니다(알 수 없는 필드 포함). markdown·blocks·pages·metadata·warnings·images·ocr_lines 를 꺼내 쓸 수 있습니다.
  • result.raise_for_error() 는 파싱 실패를 KordocParseFailed 로 바꿉니다.

파싱 옵션

버전: 아래 OCR 줄·모델 선택 API는 Python SDK 0.2.0 이상과 kordoc 엔진 4.22.0 이상이 필요합니다. npm 엔진과 Python SDK는 별도 버전으로 배포됩니다.

키워드 인자로 줍니다. 빼면 엔진 기본값이고, False 를 주면 실제로 끕니다(ocr=False 는 OCR 끔).

table_format("gfm") · html_tables · layout_tables("visual"·"keep") · classify_tables · tables · plain · script_tags · remove_header_footer · dedupe_running_headers · keep_trailing_empty_cols · keep_empty_paragraphs · include_field_placeholders · pages("1-3" 또는 [1, 3]) · images · inline_images · ocr(True·False·"force") · formula_ocr · password · ocr_lines(True·"all") · ocr_det("mobile"·"server"·OcrModelFile) · ocr_det_long_side · ocr_rec·ocr_rec_dict(OcrModelFile)

from kordoc import KordocClient, OcrModelFile

with KordocClient() as client:
    r = client.parse("스캔본.pdf", ocr=True, ocr_lines=True, ocr_det="server", ocr_det_long_side=1920,
                     ocr_rec=OcrModelFile("models/my-rec.onnx", sha256="…"))   # 상대 경로는 이 프로세스 기준 절대 경로로 보낸다
    for page in r.ocr_lines or []:                                             # list[OcrPageLines] — 옵션을 안 주면 None
        for line in page.lines:                                                # OcrLine(text, box=OcrBox(x, y, w, h), confidence, dropped)
            print(page.page_number, line.text, line.confidence, line.box)

상자는 OCR 래스터 픽셀입니다(page.scale = px/pt). 좌표 규약과 모델 검증은 OCR 줄·모델 선택을 따릅니다.

함수 값(OCR 프로바이더, 진행 콜백)과 입력 경로를 바꾸는 옵션은 받지 않습니다. 잘못된 옵션은 KordocProtocolError(code="INVALID_OPTIONS")입니다. JSON 으로 나타낼 수 없는 값(float("nan")·float("inf"), 순환 참조 등)은 워커에 보내기 전에 ValueError 로 돌려주며, 워커를 바꾸지 않습니다.

이미지

방식 사용 동작
inline (기본) parse(p) 이미지 바이트를 결과 JSON 에 base64 로 받습니다
files parse(p, image_transport="files", assets_dir="/data/assets") assets_dir 아래 요청마다 새 디렉터리에 파일로 받습니다

result.images[i].read() 를 부를 때만 바이트를 해독하거나 파일을 읽습니다. filename 은 Markdown 이 가리키는 이름, path 는 files 방식의 실제 파일입니다. files 방식의 파일은 호출자 소유이며 클라이언트를 닫아도 남습니다. 이미지가 많은 문서는 files 방식이 응답을 작게 유지합니다. 제한 시간·취소로 실행 중인 워커를 종료하면 그 요청이 쓰던 assets_dir/kordoc-<id>-* 디렉터리가 남을 수 있습니다 — assets_dir 정리는 호출자가 합니다. images=False 는 이미지 바이트 추출 자체를 생략하는 엔진 옵션으로, 전송 방식과 별개입니다.

워커 수명

설정 (KordocConfig) 기본 동작
max_workers 1 상주 워커 수. 워커 하나는 한 번에 요청 하나만 처리합니다. 코어 수로 자동으로 늘리지 않습니다
max_queue 64 워커를 기다리는 요청 수 상한. 넘으면 KordocQueueFull
request_timeout 없음 요청 제한 시간(초). 대기 큐 입장부터 결과 수신까지 — 빈 자리에서 교체 워커가 시작·워밍업하기를 기다리는 시간도 들어갑니다
start_timeout 30 워커가 ready 를 보낼 때까지
warmup_timeout 300 워밍업 문서 한 건
close_timeout 10 닫을 때 진행 중 요청을 기다리는 시간
max_worker_rss_bytes 끔 응답의 rss 가 넘으면 그 워커를 다음 작업 전에 새 워커로 바꿉니다
  • 시작: start() 를 겹쳐 부르거나 start() 없이 첫 요청을 동시에 보내도 워커는 max_workers 개만 띄웁니다. 동기 클라이언트는 여러 스레드에서 함께 써도 됩니다. start() 가 제한 시간·취소로 끊기면 같은 시작을 기다리는 다른 호출이 없을 때만 띄우던 워커를 끝내고, 있으면 시작을 이어 가 그쪽이 워커를 받습니다.
  • 제한 시간·취소: 대기 중인 요청은 큐에서만 빠집니다. 실행 중인 요청은 담당 워커를 즉시 종료·회수합니다(엔진 파싱은 중간에 멈출 수 없어서입니다). 다음 요청은 새 워커가 받습니다. 늦게 온 응답이 다른 요청에 섞이지 않습니다. 비동기에서는 Task 취소가 같은 규칙을 따릅니다.
  • 교체 워커와 제한 시간: 교체 워커가 시작·워밍업하는 동안 기다리던 요청이 제한 시간·취소로 끝나도 시작·워밍업은 이어 가고, 다음 요청이 그 워커를 받습니다. 그래서 request_timeout 이 시작·워밍업보다 짧으면 교체 직후 몇 요청이 시간 초과된 뒤 회복합니다. 교체 직후 요청까지 성공시키려면 request_timeout 을 ready 시간 + 워밍업 문서 파싱 시간 + 요청 파싱 시간보다 길게 잡습니다.
  • 장애: 워커가 끝나거나 응답이 깨지면 그 요청은 KordocWorkerCrashed 로 끝나고 자동 재시도하지 않습니다. 다음 요청에서 새 워커를 띄웁니다. 응답 직후 워커가 끝나 SDK 가 아직 알아채지 못했으면 다음 요청이 그 워커를 받아 KordocWorkerCrashed 로 끝날 수 있습니다. 재시도는 호출자가 정합니다.
  • RSS 교체: max_worker_rss_bytes 를 켜면 작업이 끝난 뒤 응답의 rss(완료 시점 값, 처리 중 최댓값 아님)를 보고 교체합니다. N 건마다 재시작하지 않습니다. 풀 메모리는 worker_info() 의 rss 합으로 봅니다. Node heap 상한은 별도로 env={"NODE_OPTIONS": "--max-old-space-size=4096"} 처럼 정합니다.
  • 워밍업: warmup(대표 문서, **options) 은 모든 워커에서 그 문서를 실제로 파싱하고, 교체된 워커도 요청을 받기 전에 같은 문서로 워밍업합니다. 결과(WarmupReport)의 경고는 그대로 전달합니다. OCR 을 건너뛴 경고가 있으면 OCR 준비가 된 것이 아닙니다. 워밍업은 처리 경로를 한 번 지나게 할 뿐 최적화 완료를 보장하지 않습니다.
    • 문서를 읽지 못한 것, 워밍업 중 워커 장애, warmup_timeout 초과는 예외가 아니라 결과로 돌려줍니다(닫힌 클라이언트·큐 포화·워커 시작 실패는 예외입니다). 교체 워커는 한 워커에서라도 성공한 문서로만 워밍업합니다. 워커를 죽이는 문서 때문에 이후 요청이 모두 실패하지 않습니다.
    • 교체 워커의 워밍업이 실패해도 요청은 실패하지 않습니다(결과는 worker_info() 의 warmup).
    • warmup() 을 겹쳐 부르면 하나씩 실행됩니다.
  • 닫기: 새 요청을 막고, 대기 요청과 시작·교체 워커를 기다리던 요청은 KordocClosed 로 끝내고(띄우던 워커는 바로 종료합니다), 진행 요청은 close_timeout 까지 기다린 뒤 워커를 종료합니다.
    • 닫기는 한 번만 실행됩니다. 겹쳐 부르거나 취소된 aclose() 를 다시 부르면 그 닫기가 끝날 때까지 기다립니다. 취소된 aclose() 도 닫기는 이어 갑니다.
    • 동기 close() 가 Ctrl-C 로 끊기면 진행 요청을 더 기다리지 않고 워커를 바로 종료하며, 다른 스레드에서 기다리던 호출은 KordocClosed 로 끝납니다. start() 가 워커를 띄우는 동안 Ctrl-C 로 끊기면 띄우던 워커를 남기지 않습니다.

바이트 입력

parse_bytes(data) 는 바이트를 SDK 소유 임시 디렉터리(temp_dir, 기본 시스템 임시 폴더 아래 kordoc-sdk-*)에 파일로 쓴 뒤 파싱합니다. 큰 입력을 NDJSON 에 다시 싣지 않기 위해서이며 임시 파일 I/O 가 생깁니다. 성공·실패·취소와 관계없이 끝나면 지우고(쓰는 중에 취소되면 쓰기가 끝나는 대로), 닫을 때는 진행 중인 쓰기를 기다린 뒤 디렉터리도 지웁니다. 원본 파일 경로가 필요한 DRM 문서 대체 경로는 바이트 입력에서 파일 입력과 같게 동작하지 않을 수 있습니다.

그 밖에

  • 워커 환경은 현재 환경을 물려받고 env 를 덧붙입니다(KORDOC_OFFLINE, KORDOC_MODEL_CACHE 등). SDK 는 요청 본문·암호를 로그에 남기지 않습니다.
  • KORDOC_ROOT 는 MCP 서버의 접근 제한입니다. SDK 는 같은 샌드박스를 제공하지 않으며, 넘긴 경로를 그대로 읽습니다.
  • 워커 프로토콜: docs/parse-worker-protocol.md

개발

npm ci && npm run build                     # 저장소 루트 — 엔진(dist/cli.js)
cd sdk/python
python -m venv .venv && . .venv/bin/activate
python -m pip install -e '.[test]'
python -m pytest                            # 실제 엔진 + 합성 문서(tests/fixtures/sdk-docs.ts) + 장애 주입 워커
python -m build

Metadata

Release files for kordoc 0.2.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 kordoc 0.2.0
File Size Uploaded
kordoc-0.2.0.tar.gz 43.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kordoc 0.2.0
File Interpreter ABI Platform
kordoc-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 72.2 kB

Release files / kordoc-0.2.0.tar.gz

Download URL kordoc-0.2.0.tar.gz
Size 43.8 kB
Tags Source
SHA-256 checksum
How to use checksums
a85a9a013cca1606bf2c5058187645aecb45ef9c328ceb8d6c29b62b9df5e862
BLAKE2b-256 checksum
How to use checksums
c770279affc58d82cf2ff8c3f7f70f27c0bbe6ff8014fd6dd04c45450c81a6d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / kordoc-0.2.0-py3-none-any.whl

Download URL kordoc-0.2.0-py3-none-any.whl
Size 28.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5a6cd4de2a840f6af770a48a9a045fdb612309dd1a03a444c5fdd38bac603ae8
BLAKE2b-256 checksum
How to use checksums
5e0ed5150db2b283189a37235ce3f4fb6063e2c8c2013bc0efc1d04a207843d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

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