from hwpapi import App
app = App()
# Lifecycle on App
app.open("report.hwp")
app.save()
app.save_as("report.pdf")
# Content on app.doc
text = app.doc.text
app.doc.insert_text("new paragraph\n")
app.doc.fields["author"] = "νκΈΈλ"
app.doc.page.setup(width="210mm", height="297mm")
app.close()
app.quit()App and Document
The two-class v2 facade
The split
hwpapi v2 divides the public surface into two top-level classes:
| Class | Owns | Obtained from |
|---|---|---|
App |
COM engine lifecycle, window visibility, open/save/close/quit | App() |
Document |
Everything scoped to one open document β text, cursor, collections, page layout | app.doc |
This is the central design choice of v2. The v1 App carried 82+ public members; the v2 App has β€ 15. Every document-scoped member moved to Document.
When to use which
- App β connect/disconnect, open a file, save or export, toggle window visibility, reach the escape hatch.
- Document (
app.doc) β read/write text, navigate the cursor, insert things, access collections (fields,bookmarks,images, β¦), configure page layout.
App β the lifecycle layer
The full v2 App public surface is:
| Member | Kind | Purpose |
|---|---|---|
App(new_app=False, is_visible=True, dll_path=None, engine=None) |
constructor | Connect to HWP |
open(path) |
method | Open a .hwp / .hwpx file |
new() |
method | Create a blank document |
close() |
method | Close the active document |
save() |
method | Save in place |
save_as(path, *, as_block=False) |
method | Save to a new file (format inferred from extension) |
reload() |
method | Rebind to an existing COM engine |
quit() |
method | Tear down the COM engine |
visible |
property (r/w) | Window visibility |
doc |
property | The active Document |
engine |
property | The Engine β escape hatch |
api |
property | Raw HWP COM handle β ultimate escape hatch |
actions |
property | The action catalogue β escape hatch |
__enter__ / __exit__ |
context manager | Auto-closes on exit |
Context-manager usage handles cleanup for you:
from hwpapi import App
with App() as app:
app.open("template.hwp")
app.doc.insert_text("Generated by hwpapi\n")
app.save_as("generated.pdf")
# app.close() + app.quit() happen here even if an exception was raisedDocument β the per-document layer
app.doc returns the same Document instance on every access (@cached_property). It owns:
- Text β
doc.text(read/write),doc.get_text(),doc.insert_text(s),doc.get_selected_text(),doc.selection - Navigation β
doc.cursor.goto_page(n),doc.cursor.move_to_field(name),doc.cursor.in_table(),doc.cursor.get_charshape(),doc.cursor.get_parashape() - Clipboard β
doc.copy(),doc.cut(),doc.paste(),doc.delete() - Undo β
doc.undo(),doc.redo() - Search β
doc.find_text(q),doc.replace_all(find, replace) - Structure β
doc.insert_page_break(),doc.insert_line_break(),doc.insert_paragraph_break(),doc.insert_tab(),doc.insert_heading(level, text) - Inserts β
doc.insert_file(path),doc.insert_picture(path) - Page setup β
doc.page.setup(...) - Counters β
doc.page_count,doc.current_page,doc.get_filepath(),doc.get_hwnd() - Collections (dict-like) β
doc.fields,doc.bookmarks,doc.hyperlinks,doc.images,doc.styles,doc.paragraphs,doc.tables - Scanner β
doc.scan(...)context manager
Why not merge them?
The v1 App was a god-object: 82 public members mixing lifecycle, content, formatting, navigation, and low-level utilities. The split serves three goals:
- Discoverability.
dir(app)now fits on one screen; everything else lives underapp.doc.*with IDE tab completion. - Lifetime. A
Documentstops being useful when the underlying file closes. Splitting the surface makes the invalidation boundary explicit β future v2.1 work on multi-document support targetsapp.documents[β¦]returning a newDocument, without touchingApp. - Teachability. βApp = COM engine, Document = contentsβ is a sentence. βApp = everything HWP-relatedβ was a paragraph.
See also
- Collections guide β the dict-like accessors under
app.doc.* - Context scopes β
charshape_scope,parashape_scope,styled_text - Low-level escape hatch β
hwpapi.low.* - Migration v1 β v2 β full 1:1 table