python-hwpx 1.2__tar.gz → 1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python-hwpx-1.4/PKG-INFO +114 -0
- python-hwpx-1.4/README.md +84 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/pyproject.toml +1 -1
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/document.py +164 -1
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/__init__.py +77 -1
- python-hwpx-1.4/src/hwpx/oxml/body.py +432 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/common.py +2 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/document.py +742 -37
- python-hwpx-1.4/src/hwpx/oxml/header.py +1366 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/parser.py +7 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/package.py +88 -0
- python-hwpx-1.4/src/python_hwpx.egg-info/PKG-INFO +114 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/python_hwpx.egg-info/SOURCES.txt +2 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/tests/test_document_formatting.py +99 -0
- python-hwpx-1.4/tests/test_inline_models.py +113 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/tests/test_integration_hwpx_compatibility.py +89 -0
- python-hwpx-1.4/tests/test_oxml_parsing.py +385 -0
- python-hwpx-1.4/tests/test_section_headers.py +143 -0
- python-hwpx-1.2/PKG-INFO +0 -196
- python-hwpx-1.2/README.md +0 -166
- python-hwpx-1.2/src/hwpx/oxml/body.py +0 -151
- python-hwpx-1.2/src/hwpx/oxml/header.py +0 -543
- python-hwpx-1.2/src/python_hwpx.egg-info/PKG-INFO +0 -196
- python-hwpx-1.2/tests/test_oxml_parsing.py +0 -159
- {python-hwpx-1.2 → python-hwpx-1.4}/LICENSE +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/setup.cfg +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/__init__.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/data/Skeleton.hwpx +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/opc/package.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/schema.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/oxml/utils.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/templates.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/__init__.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/_schemas/header.xsd +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/_schemas/section.xsd +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/object_finder.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/text_extractor.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/hwpx/tools/validator.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/python_hwpx.egg-info/entry_points.txt +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/python_hwpx.egg-info/requires.txt +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/src/python_hwpx.egg-info/top_level.txt +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/tests/test_memo_and_style_editing.py +0 -0
- {python-hwpx-1.2 → python-hwpx-1.4}/tests/test_text_extractor_annotations.py +0 -0
python-hwpx-1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-hwpx
|
|
3
|
+
Version: 1.4
|
|
4
|
+
Summary: Hancom HWPX 패키지를 로드하고 편집하기 위한 Python 유틸리티 모음
|
|
5
|
+
Author: python-hwpx Maintainers
|
|
6
|
+
License: Non-Commercial License
|
|
7
|
+
Project-URL: Homepage, https://github.com/airmang/python-hwpx
|
|
8
|
+
Project-URL: Documentation, https://github.com/airmang/python-hwpx/tree/main/docs
|
|
9
|
+
Project-URL: Issues, https://github.com/airmang/python-hwpx/issues
|
|
10
|
+
Keywords: hwp,hwpx,hancom,opc,xml
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: lxml<6,>=4.9
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
26
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest>=7.4; extra == "test"
|
|
30
|
+
|
|
31
|
+
# python-hwpx
|
|
32
|
+
|
|
33
|
+
`python-hwpx`는 Hancom HWPX 문서를 읽고, 편집하고, 자동화 스크립트로 재가공하기 위한 파이썬 도구 모음입니다. Open Packaging Convention(OPC) 컨테이너를 검사하는 저수준 도구부터 문단·표·메모를 쉽게 다루는 고수준 API, 텍스트 추출과 객체 검색 유틸리티까지 하나로 제공합니다.
|
|
34
|
+
|
|
35
|
+
## 특징 요약
|
|
36
|
+
|
|
37
|
+
- **패키지 로딩과 검증** – `hwpx.opc.package.HwpxPackage`로 `mimetype`, `container.xml`, `version.xml`을 확인하며 모든 파트를 메모리에 적재합니다.
|
|
38
|
+
- **문서 편집 API** – `hwpx.document.HwpxDocument`는 문단과 표, 메모, 헤더 속성을 파이썬 객체로 노출하고 새 콘텐츠를 손쉽게 추가합니다. 섹션 머리말·꼬리말을 수정하면 `<hp:headerApply>`/`<hp:footerApply>`와 마스터 페이지 링크도 함께 갱신합니다.
|
|
39
|
+
- **타입이 지정된 본문 모델** – `hwpx.oxml.body`는 표·컨트롤·인라인 도형·변경 추적 태그를 데이터 클래스에 매핑하고, `HwpxOxmlParagraph.model`/`HwpxOxmlRun.model`로 이를 조회·수정한 뒤 XML로 되돌릴 수 있도록 지원합니다.
|
|
40
|
+
- **메모와 필드 앵커** – `add_memo_with_anchor()`로 메모를 생성하면서 MEMO 필드 컨트롤을 자동 삽입해 한/글에서 바로 표시되도록 합니다.
|
|
41
|
+
- **헤더 참조 목록 탐색** – 글머리표, 문단 속성, 스타일, 변경 추적 항목, 작성자 정보를 데이터클래스로 파싱하고 `document.bullets`·`document.styles` 같은 조회 헬퍼로 ID 기반 검색을 단순화했습니다.
|
|
42
|
+
- **바탕쪽·이력·버전 파트 제어** – 매니페스트에 포함된 master-page/history/version 파트를 `document.master_pages`, `document.histories`, `document.version`으로 직접 편집하고 저장합니다.
|
|
43
|
+
- **스타일 기반 텍스트 치환** – 런 서식(색상, 밑줄, `charPrIDRef`)으로 필터링해 텍스트를 선택적으로 교체하거나 삭제합니다. 하이라이트
|
|
44
|
+
마커나 태그로 분리된 문자열도 서식을 유지한 채 치환합니다.
|
|
45
|
+
- **텍스트 추출 파이프라인** – `hwpx.tools.text_extractor.TextExtractor`는 하이라이트, 각주, 컨트롤을 원하는 방식으로 표현하며 문단 텍스트를 반환합니다.
|
|
46
|
+
- **풍부한 문서** – 빠른 시작, 50개의 사용 패턴, 설치/FAQ/스키마 개요를 Sphinx 기반 웹 문서로 제공합니다.
|
|
47
|
+
|
|
48
|
+
## 설치
|
|
49
|
+
|
|
50
|
+
PyPI에서 최신 버전을 바로 설치할 수 있습니다.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python -m pip install python-hwpx
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
개발 버전이나 문서 빌드를 직접 수정하려면 저장소를 클론한 뒤 편집 가능한 설치를 사용하세요.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/<your-org>/python-hwpx.git
|
|
60
|
+
cd python-hwpx
|
|
61
|
+
python -m pip install -e .[dev]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Sphinx 문서는 `docs/` 아래에 있으며, `python -m pip install -r docs/requirements.txt` 후 `make -C docs html`로 로컬 미리보기가 가능합니다.
|
|
65
|
+
|
|
66
|
+
## 5분 안에 맛보기
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from io import BytesIO
|
|
70
|
+
|
|
71
|
+
from hwpx.document import HwpxDocument
|
|
72
|
+
from hwpx.templates import blank_document_bytes
|
|
73
|
+
|
|
74
|
+
# 1) 빈 템플릿으로 문서 열기
|
|
75
|
+
source = BytesIO(blank_document_bytes())
|
|
76
|
+
document = HwpxDocument.open(source)
|
|
77
|
+
print("sections:", len(document.sections))
|
|
78
|
+
|
|
79
|
+
# 2) 문단과 표, 메모 추가
|
|
80
|
+
section = document.sections[0]
|
|
81
|
+
paragraph = document.add_paragraph("자동 생성한 문단", section=section)
|
|
82
|
+
table = document.add_table(rows=2, cols=2, section=section)
|
|
83
|
+
table.set_cell_text(0, 0, "항목")
|
|
84
|
+
table.set_cell_text(0, 1, "값")
|
|
85
|
+
table.set_cell_text(1, 0, "문단 수")
|
|
86
|
+
table.set_cell_text(1, 1, str(len(document.paragraphs)))
|
|
87
|
+
document.add_memo_with_anchor("배포 전 검토", paragraph=paragraph, memo_shape_id_ref="0")
|
|
88
|
+
|
|
89
|
+
# 3) 다른 이름으로 저장
|
|
90
|
+
document.save("output/example.hwpx")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
더 많은 실전 패턴은 [빠른 시작](docs/quickstart.md)과 [사용 가이드](docs/usage.md)의 "빠른 예제 모음"에서 확인할 수 있습니다.
|
|
94
|
+
|
|
95
|
+
## 문서
|
|
96
|
+
[사용법](https://airmang.github.io/python-hwpx/)
|
|
97
|
+
|
|
98
|
+
## 예제와 도구
|
|
99
|
+
|
|
100
|
+
- `examples/` 디렉터리는 텍스트 추출, 객체 검색, QA 체크리스트 생성 예제를 제공합니다. PyPI 패키지에는 포함되지 않으므로 필요하면 저장소를 클론하거나 웹 문서의 코드 스니펫을 활용하세요.
|
|
101
|
+
- `hwpx.templates.blank_document_bytes()`는 추가 리소스 없이 빈 HWPX 문서를 만들 수 있는 내장 템플릿을 제공합니다.
|
|
102
|
+
|
|
103
|
+
## 알려진 제약
|
|
104
|
+
|
|
105
|
+
- `add_shape()`/`add_control()`은 한/글이 요구하는 모든 하위 요소를 생성하지 않으므로, 복잡한 개체를 추가할 때는 편집기에서 열어 검증해 주세요.
|
|
106
|
+
|
|
107
|
+
## 기여하기
|
|
108
|
+
|
|
109
|
+
버그 리포트와 개선 제안은 언제나 환영합니다. 개발 환경 설정과 테스트 방법은 [CONTRIBUTING.md](CONTRIBUTING.md)를 참고하세요.
|
|
110
|
+
|
|
111
|
+
## 라이선스와 연락처
|
|
112
|
+
|
|
113
|
+
- 라이선스: [LICENSE](LICENSE)
|
|
114
|
+
- 문의: 이슈 트래커 또는 kokyuhyun@hotmail.com
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# python-hwpx
|
|
2
|
+
|
|
3
|
+
`python-hwpx`는 Hancom HWPX 문서를 읽고, 편집하고, 자동화 스크립트로 재가공하기 위한 파이썬 도구 모음입니다. Open Packaging Convention(OPC) 컨테이너를 검사하는 저수준 도구부터 문단·표·메모를 쉽게 다루는 고수준 API, 텍스트 추출과 객체 검색 유틸리티까지 하나로 제공합니다.
|
|
4
|
+
|
|
5
|
+
## 특징 요약
|
|
6
|
+
|
|
7
|
+
- **패키지 로딩과 검증** – `hwpx.opc.package.HwpxPackage`로 `mimetype`, `container.xml`, `version.xml`을 확인하며 모든 파트를 메모리에 적재합니다.
|
|
8
|
+
- **문서 편집 API** – `hwpx.document.HwpxDocument`는 문단과 표, 메모, 헤더 속성을 파이썬 객체로 노출하고 새 콘텐츠를 손쉽게 추가합니다. 섹션 머리말·꼬리말을 수정하면 `<hp:headerApply>`/`<hp:footerApply>`와 마스터 페이지 링크도 함께 갱신합니다.
|
|
9
|
+
- **타입이 지정된 본문 모델** – `hwpx.oxml.body`는 표·컨트롤·인라인 도형·변경 추적 태그를 데이터 클래스에 매핑하고, `HwpxOxmlParagraph.model`/`HwpxOxmlRun.model`로 이를 조회·수정한 뒤 XML로 되돌릴 수 있도록 지원합니다.
|
|
10
|
+
- **메모와 필드 앵커** – `add_memo_with_anchor()`로 메모를 생성하면서 MEMO 필드 컨트롤을 자동 삽입해 한/글에서 바로 표시되도록 합니다.
|
|
11
|
+
- **헤더 참조 목록 탐색** – 글머리표, 문단 속성, 스타일, 변경 추적 항목, 작성자 정보를 데이터클래스로 파싱하고 `document.bullets`·`document.styles` 같은 조회 헬퍼로 ID 기반 검색을 단순화했습니다.
|
|
12
|
+
- **바탕쪽·이력·버전 파트 제어** – 매니페스트에 포함된 master-page/history/version 파트를 `document.master_pages`, `document.histories`, `document.version`으로 직접 편집하고 저장합니다.
|
|
13
|
+
- **스타일 기반 텍스트 치환** – 런 서식(색상, 밑줄, `charPrIDRef`)으로 필터링해 텍스트를 선택적으로 교체하거나 삭제합니다. 하이라이트
|
|
14
|
+
마커나 태그로 분리된 문자열도 서식을 유지한 채 치환합니다.
|
|
15
|
+
- **텍스트 추출 파이프라인** – `hwpx.tools.text_extractor.TextExtractor`는 하이라이트, 각주, 컨트롤을 원하는 방식으로 표현하며 문단 텍스트를 반환합니다.
|
|
16
|
+
- **풍부한 문서** – 빠른 시작, 50개의 사용 패턴, 설치/FAQ/스키마 개요를 Sphinx 기반 웹 문서로 제공합니다.
|
|
17
|
+
|
|
18
|
+
## 설치
|
|
19
|
+
|
|
20
|
+
PyPI에서 최신 버전을 바로 설치할 수 있습니다.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python -m pip install python-hwpx
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
개발 버전이나 문서 빌드를 직접 수정하려면 저장소를 클론한 뒤 편집 가능한 설치를 사용하세요.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/<your-org>/python-hwpx.git
|
|
30
|
+
cd python-hwpx
|
|
31
|
+
python -m pip install -e .[dev]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Sphinx 문서는 `docs/` 아래에 있으며, `python -m pip install -r docs/requirements.txt` 후 `make -C docs html`로 로컬 미리보기가 가능합니다.
|
|
35
|
+
|
|
36
|
+
## 5분 안에 맛보기
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from io import BytesIO
|
|
40
|
+
|
|
41
|
+
from hwpx.document import HwpxDocument
|
|
42
|
+
from hwpx.templates import blank_document_bytes
|
|
43
|
+
|
|
44
|
+
# 1) 빈 템플릿으로 문서 열기
|
|
45
|
+
source = BytesIO(blank_document_bytes())
|
|
46
|
+
document = HwpxDocument.open(source)
|
|
47
|
+
print("sections:", len(document.sections))
|
|
48
|
+
|
|
49
|
+
# 2) 문단과 표, 메모 추가
|
|
50
|
+
section = document.sections[0]
|
|
51
|
+
paragraph = document.add_paragraph("자동 생성한 문단", section=section)
|
|
52
|
+
table = document.add_table(rows=2, cols=2, section=section)
|
|
53
|
+
table.set_cell_text(0, 0, "항목")
|
|
54
|
+
table.set_cell_text(0, 1, "값")
|
|
55
|
+
table.set_cell_text(1, 0, "문단 수")
|
|
56
|
+
table.set_cell_text(1, 1, str(len(document.paragraphs)))
|
|
57
|
+
document.add_memo_with_anchor("배포 전 검토", paragraph=paragraph, memo_shape_id_ref="0")
|
|
58
|
+
|
|
59
|
+
# 3) 다른 이름으로 저장
|
|
60
|
+
document.save("output/example.hwpx")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
더 많은 실전 패턴은 [빠른 시작](docs/quickstart.md)과 [사용 가이드](docs/usage.md)의 "빠른 예제 모음"에서 확인할 수 있습니다.
|
|
64
|
+
|
|
65
|
+
## 문서
|
|
66
|
+
[사용법](https://airmang.github.io/python-hwpx/)
|
|
67
|
+
|
|
68
|
+
## 예제와 도구
|
|
69
|
+
|
|
70
|
+
- `examples/` 디렉터리는 텍스트 추출, 객체 검색, QA 체크리스트 생성 예제를 제공합니다. PyPI 패키지에는 포함되지 않으므로 필요하면 저장소를 클론하거나 웹 문서의 코드 스니펫을 활용하세요.
|
|
71
|
+
- `hwpx.templates.blank_document_bytes()`는 추가 리소스 없이 빈 HWPX 문서를 만들 수 있는 내장 템플릿을 제공합니다.
|
|
72
|
+
|
|
73
|
+
## 알려진 제약
|
|
74
|
+
|
|
75
|
+
- `add_shape()`/`add_control()`은 한/글이 요구하는 모든 하위 요소를 생성하지 않으므로, 복잡한 개체를 추가할 때는 편집기에서 열어 검증해 주세요.
|
|
76
|
+
|
|
77
|
+
## 기여하기
|
|
78
|
+
|
|
79
|
+
버그 리포트와 개선 제안은 언제나 환영합니다. 개발 환경 설정과 테스트 방법은 [CONTRIBUTING.md](CONTRIBUTING.md)를 참고하세요.
|
|
80
|
+
|
|
81
|
+
## 라이선스와 연락처
|
|
82
|
+
|
|
83
|
+
- 라이선스: [LICENSE](LICENSE)
|
|
84
|
+
- 문의: 이슈 트래커 또는 kokyuhyun@hotmail.com
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-hwpx"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4"
|
|
8
8
|
description = "Hancom HWPX 패키지를 로드하고 편집하기 위한 Python 유틸리티 모음"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { text = "Non-Commercial License" }
|
|
@@ -10,16 +10,25 @@ from os import PathLike
|
|
|
10
10
|
from typing import BinaryIO, Iterator, List, Tuple
|
|
11
11
|
|
|
12
12
|
from .oxml import (
|
|
13
|
+
Bullet,
|
|
13
14
|
HwpxOxmlDocument,
|
|
14
15
|
HwpxOxmlHeader,
|
|
16
|
+
HwpxOxmlHistory,
|
|
15
17
|
HwpxOxmlInlineObject,
|
|
18
|
+
HwpxOxmlMasterPage,
|
|
16
19
|
HwpxOxmlMemo,
|
|
17
20
|
HwpxOxmlParagraph,
|
|
18
21
|
HwpxOxmlRun,
|
|
19
22
|
HwpxOxmlSection,
|
|
23
|
+
HwpxOxmlSectionHeaderFooter,
|
|
20
24
|
HwpxOxmlTable,
|
|
25
|
+
HwpxOxmlVersion,
|
|
21
26
|
MemoShape,
|
|
27
|
+
ParagraphProperty,
|
|
22
28
|
RunStyle,
|
|
29
|
+
Style,
|
|
30
|
+
TrackChange,
|
|
31
|
+
TrackChangeAuthor,
|
|
23
32
|
)
|
|
24
33
|
from .package import HwpxPackage
|
|
25
34
|
from .templates import blank_document_bytes
|
|
@@ -83,6 +92,21 @@ class HwpxDocument:
|
|
|
83
92
|
"""Return the header parts referenced by the document."""
|
|
84
93
|
return self._root.headers
|
|
85
94
|
|
|
95
|
+
@property
|
|
96
|
+
def master_pages(self) -> List[HwpxOxmlMasterPage]:
|
|
97
|
+
"""Return the master-page parts declared in the manifest."""
|
|
98
|
+
return self._root.master_pages
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def histories(self) -> List[HwpxOxmlHistory]:
|
|
102
|
+
"""Return document history parts referenced by the manifest."""
|
|
103
|
+
return self._root.histories
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def version(self) -> HwpxOxmlVersion | None:
|
|
107
|
+
"""Return the version metadata part if present."""
|
|
108
|
+
return self._root.version
|
|
109
|
+
|
|
86
110
|
@property
|
|
87
111
|
def memo_shapes(self) -> dict[str, MemoShape]:
|
|
88
112
|
"""Return memo shapes available in the header reference lists."""
|
|
@@ -94,6 +118,65 @@ class HwpxDocument:
|
|
|
94
118
|
|
|
95
119
|
return self._root.memo_shape(memo_shape_id_ref)
|
|
96
120
|
|
|
121
|
+
@property
|
|
122
|
+
def bullets(self) -> dict[str, Bullet]:
|
|
123
|
+
"""Return bullet definitions declared in header reference lists."""
|
|
124
|
+
|
|
125
|
+
return self._root.bullets
|
|
126
|
+
|
|
127
|
+
def bullet(self, bullet_id_ref: int | str | None) -> Bullet | None:
|
|
128
|
+
"""Return the bullet definition referenced by *bullet_id_ref*."""
|
|
129
|
+
|
|
130
|
+
return self._root.bullet(bullet_id_ref)
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def paragraph_properties(self) -> dict[str, ParagraphProperty]:
|
|
134
|
+
"""Return paragraph property definitions declared in headers."""
|
|
135
|
+
|
|
136
|
+
return self._root.paragraph_properties
|
|
137
|
+
|
|
138
|
+
def paragraph_property(
|
|
139
|
+
self, para_pr_id_ref: int | str | None
|
|
140
|
+
) -> ParagraphProperty | None:
|
|
141
|
+
"""Return the paragraph property referenced by *para_pr_id_ref*."""
|
|
142
|
+
|
|
143
|
+
return self._root.paragraph_property(para_pr_id_ref)
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def styles(self) -> dict[str, Style]:
|
|
147
|
+
"""Return style definitions available in the document."""
|
|
148
|
+
|
|
149
|
+
return self._root.styles
|
|
150
|
+
|
|
151
|
+
def style(self, style_id_ref: int | str | None) -> Style | None:
|
|
152
|
+
"""Return the style definition referenced by *style_id_ref*."""
|
|
153
|
+
|
|
154
|
+
return self._root.style(style_id_ref)
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def track_changes(self) -> dict[str, TrackChange]:
|
|
158
|
+
"""Return tracked change metadata declared in the headers."""
|
|
159
|
+
|
|
160
|
+
return self._root.track_changes
|
|
161
|
+
|
|
162
|
+
def track_change(self, change_id_ref: int | str | None) -> TrackChange | None:
|
|
163
|
+
"""Return tracked change metadata referenced by *change_id_ref*."""
|
|
164
|
+
|
|
165
|
+
return self._root.track_change(change_id_ref)
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def track_change_authors(self) -> dict[str, TrackChangeAuthor]:
|
|
169
|
+
"""Return tracked change author metadata declared in the headers."""
|
|
170
|
+
|
|
171
|
+
return self._root.track_change_authors
|
|
172
|
+
|
|
173
|
+
def track_change_author(
|
|
174
|
+
self, author_id_ref: int | str | None
|
|
175
|
+
) -> TrackChangeAuthor | None:
|
|
176
|
+
"""Return tracked change author details referenced by *author_id_ref*."""
|
|
177
|
+
|
|
178
|
+
return self._root.track_change_author(author_id_ref)
|
|
179
|
+
|
|
97
180
|
@property
|
|
98
181
|
def memos(self) -> List[HwpxOxmlMemo]:
|
|
99
182
|
"""Return all memo entries declared in every section."""
|
|
@@ -389,11 +472,17 @@ class HwpxDocument:
|
|
|
389
472
|
remaining = limit - replacements
|
|
390
473
|
if remaining <= 0:
|
|
391
474
|
break
|
|
392
|
-
|
|
475
|
+
original_char_pr = run.char_pr_id_ref
|
|
476
|
+
replaced_here = run.replace_text(
|
|
393
477
|
search,
|
|
394
478
|
replacement,
|
|
395
479
|
count=remaining,
|
|
396
480
|
)
|
|
481
|
+
if replaced_here and original_char_pr is not None:
|
|
482
|
+
# Ensure the run retains its original formatting reference even
|
|
483
|
+
# if XML nodes were rewritten during substitution.
|
|
484
|
+
run.char_pr_id_ref = original_char_pr
|
|
485
|
+
replacements += replaced_here
|
|
397
486
|
if limit is not None and replacements >= limit:
|
|
398
487
|
break
|
|
399
488
|
return replacements
|
|
@@ -533,6 +622,80 @@ class HwpxDocument:
|
|
|
533
622
|
char_pr_id_ref=char_pr_id_ref,
|
|
534
623
|
)
|
|
535
624
|
|
|
625
|
+
def set_header_text(
|
|
626
|
+
self,
|
|
627
|
+
text: str,
|
|
628
|
+
*,
|
|
629
|
+
section: HwpxOxmlSection | None = None,
|
|
630
|
+
section_index: int | None = None,
|
|
631
|
+
page_type: str = "BOTH",
|
|
632
|
+
) -> HwpxOxmlSectionHeaderFooter:
|
|
633
|
+
"""Ensure the requested section contains a header for *page_type* and set its text."""
|
|
634
|
+
|
|
635
|
+
target_section = section
|
|
636
|
+
if target_section is None and section_index is not None:
|
|
637
|
+
target_section = self._root.sections[section_index]
|
|
638
|
+
if target_section is None:
|
|
639
|
+
if not self._root.sections:
|
|
640
|
+
raise ValueError("document does not contain any sections")
|
|
641
|
+
target_section = self._root.sections[-1]
|
|
642
|
+
return target_section.properties.set_header_text(text, page_type=page_type)
|
|
643
|
+
|
|
644
|
+
def set_footer_text(
|
|
645
|
+
self,
|
|
646
|
+
text: str,
|
|
647
|
+
*,
|
|
648
|
+
section: HwpxOxmlSection | None = None,
|
|
649
|
+
section_index: int | None = None,
|
|
650
|
+
page_type: str = "BOTH",
|
|
651
|
+
) -> HwpxOxmlSectionHeaderFooter:
|
|
652
|
+
"""Ensure the requested section contains a footer for *page_type* and set its text."""
|
|
653
|
+
|
|
654
|
+
target_section = section
|
|
655
|
+
if target_section is None and section_index is not None:
|
|
656
|
+
target_section = self._root.sections[section_index]
|
|
657
|
+
if target_section is None:
|
|
658
|
+
if not self._root.sections:
|
|
659
|
+
raise ValueError("document does not contain any sections")
|
|
660
|
+
target_section = self._root.sections[-1]
|
|
661
|
+
return target_section.properties.set_footer_text(text, page_type=page_type)
|
|
662
|
+
|
|
663
|
+
def remove_header(
|
|
664
|
+
self,
|
|
665
|
+
*,
|
|
666
|
+
section: HwpxOxmlSection | None = None,
|
|
667
|
+
section_index: int | None = None,
|
|
668
|
+
page_type: str = "BOTH",
|
|
669
|
+
) -> None:
|
|
670
|
+
"""Remove the header linked to *page_type* from the requested section if present."""
|
|
671
|
+
|
|
672
|
+
target_section = section
|
|
673
|
+
if target_section is None and section_index is not None:
|
|
674
|
+
target_section = self._root.sections[section_index]
|
|
675
|
+
if target_section is None:
|
|
676
|
+
if not self._root.sections:
|
|
677
|
+
return
|
|
678
|
+
target_section = self._root.sections[-1]
|
|
679
|
+
target_section.properties.remove_header(page_type=page_type)
|
|
680
|
+
|
|
681
|
+
def remove_footer(
|
|
682
|
+
self,
|
|
683
|
+
*,
|
|
684
|
+
section: HwpxOxmlSection | None = None,
|
|
685
|
+
section_index: int | None = None,
|
|
686
|
+
page_type: str = "BOTH",
|
|
687
|
+
) -> None:
|
|
688
|
+
"""Remove the footer linked to *page_type* from the requested section if present."""
|
|
689
|
+
|
|
690
|
+
target_section = section
|
|
691
|
+
if target_section is None and section_index is not None:
|
|
692
|
+
target_section = self._root.sections[section_index]
|
|
693
|
+
if target_section is None:
|
|
694
|
+
if not self._root.sections:
|
|
695
|
+
return
|
|
696
|
+
target_section = self._root.sections[-1]
|
|
697
|
+
target_section.properties.remove_footer(page_type=page_type)
|
|
698
|
+
|
|
536
699
|
def save(
|
|
537
700
|
self,
|
|
538
701
|
path_or_stream: str | PathLike[str] | BinaryIO | None = None,
|
|
@@ -19,7 +19,9 @@ from .document import (
|
|
|
19
19
|
DocumentNumbering,
|
|
20
20
|
HwpxOxmlDocument,
|
|
21
21
|
HwpxOxmlHeader,
|
|
22
|
+
HwpxOxmlHistory,
|
|
22
23
|
HwpxOxmlInlineObject,
|
|
24
|
+
HwpxOxmlMasterPage,
|
|
23
25
|
HwpxOxmlMemo,
|
|
24
26
|
HwpxOxmlMemoGroup,
|
|
25
27
|
HwpxOxmlParagraph,
|
|
@@ -30,6 +32,7 @@ from .document import (
|
|
|
30
32
|
HwpxOxmlTable,
|
|
31
33
|
HwpxOxmlTableCell,
|
|
32
34
|
HwpxOxmlTableRow,
|
|
35
|
+
HwpxOxmlVersion,
|
|
33
36
|
PageMargins,
|
|
34
37
|
PageSize,
|
|
35
38
|
RunStyle,
|
|
@@ -39,6 +42,9 @@ from .document import (
|
|
|
39
42
|
from .header import (
|
|
40
43
|
BeginNum,
|
|
41
44
|
BorderFillList,
|
|
45
|
+
Bullet,
|
|
46
|
+
BulletList,
|
|
47
|
+
BulletParaHead,
|
|
42
48
|
CharProperty,
|
|
43
49
|
CharPropertyList,
|
|
44
50
|
DocOption,
|
|
@@ -56,16 +62,48 @@ from .header import (
|
|
|
56
62
|
MemoProperties,
|
|
57
63
|
MemoShape,
|
|
58
64
|
NumberingList,
|
|
65
|
+
ParagraphAlignment,
|
|
66
|
+
ParagraphAutoSpacing,
|
|
67
|
+
ParagraphBreakSetting,
|
|
68
|
+
ParagraphBorder,
|
|
69
|
+
ParagraphHeading,
|
|
70
|
+
ParagraphLineSpacing,
|
|
71
|
+
ParagraphMargin,
|
|
72
|
+
ParagraphProperty,
|
|
73
|
+
ParagraphPropertyList,
|
|
59
74
|
RefList,
|
|
75
|
+
Style,
|
|
76
|
+
StyleList,
|
|
60
77
|
TabProperties,
|
|
78
|
+
TrackChange,
|
|
79
|
+
TrackChangeAuthor,
|
|
80
|
+
TrackChangeAuthorList,
|
|
61
81
|
TrackChangeConfig,
|
|
82
|
+
TrackChangeList,
|
|
62
83
|
memo_shape_from_attributes,
|
|
63
84
|
parse_begin_num,
|
|
85
|
+
parse_bullet,
|
|
86
|
+
parse_bullet_para_head,
|
|
87
|
+
parse_bullets,
|
|
64
88
|
parse_doc_option,
|
|
65
89
|
parse_header_element,
|
|
66
90
|
parse_memo_properties,
|
|
67
91
|
parse_memo_shape,
|
|
92
|
+
parse_paragraph_alignment,
|
|
93
|
+
parse_paragraph_auto_spacing,
|
|
94
|
+
parse_paragraph_border,
|
|
95
|
+
parse_paragraph_break_setting,
|
|
96
|
+
parse_paragraph_line_spacing,
|
|
97
|
+
parse_paragraph_margin,
|
|
98
|
+
parse_paragraph_property,
|
|
99
|
+
parse_paragraph_properties,
|
|
68
100
|
parse_ref_list,
|
|
101
|
+
parse_style,
|
|
102
|
+
parse_styles,
|
|
103
|
+
parse_track_change,
|
|
104
|
+
parse_track_change_author,
|
|
105
|
+
parse_track_change_authors,
|
|
106
|
+
parse_track_changes,
|
|
69
107
|
)
|
|
70
108
|
from .parser import element_to_model, parse_header_xml, parse_section_xml
|
|
71
109
|
from .schema import load_schema
|
|
@@ -74,6 +112,9 @@ from .utils import XmlSource
|
|
|
74
112
|
__all__ = [
|
|
75
113
|
"BeginNum",
|
|
76
114
|
"BorderFillList",
|
|
115
|
+
"Bullet",
|
|
116
|
+
"BulletList",
|
|
117
|
+
"BulletParaHead",
|
|
77
118
|
"CharProperty",
|
|
78
119
|
"CharPropertyList",
|
|
79
120
|
"DocOption",
|
|
@@ -88,7 +129,9 @@ __all__ = [
|
|
|
88
129
|
"DocumentNumbering",
|
|
89
130
|
"HwpxOxmlDocument",
|
|
90
131
|
"HwpxOxmlHeader",
|
|
132
|
+
"HwpxOxmlHistory",
|
|
91
133
|
"HwpxOxmlInlineObject",
|
|
134
|
+
"HwpxOxmlMasterPage",
|
|
92
135
|
"HwpxOxmlMemo",
|
|
93
136
|
"HwpxOxmlMemoGroup",
|
|
94
137
|
"HwpxOxmlParagraph",
|
|
@@ -99,6 +142,7 @@ __all__ = [
|
|
|
99
142
|
"HwpxOxmlTable",
|
|
100
143
|
"HwpxOxmlTableCell",
|
|
101
144
|
"HwpxOxmlTableRow",
|
|
145
|
+
"HwpxOxmlVersion",
|
|
102
146
|
"KeyDerivation",
|
|
103
147
|
"KeyEncryption",
|
|
104
148
|
"LinkInfo",
|
|
@@ -106,6 +150,15 @@ __all__ = [
|
|
|
106
150
|
"MemoProperties",
|
|
107
151
|
"MemoShape",
|
|
108
152
|
"NumberingList",
|
|
153
|
+
"ParagraphAlignment",
|
|
154
|
+
"ParagraphAutoSpacing",
|
|
155
|
+
"ParagraphBreakSetting",
|
|
156
|
+
"ParagraphBorder",
|
|
157
|
+
"ParagraphHeading",
|
|
158
|
+
"ParagraphLineSpacing",
|
|
159
|
+
"ParagraphMargin",
|
|
160
|
+
"ParagraphProperty",
|
|
161
|
+
"ParagraphPropertyList",
|
|
109
162
|
"Paragraph",
|
|
110
163
|
"PageMargins",
|
|
111
164
|
"PageSize",
|
|
@@ -115,22 +168,45 @@ __all__ = [
|
|
|
115
168
|
"Run",
|
|
116
169
|
"Section",
|
|
117
170
|
"SectionStartNumbering",
|
|
171
|
+
"Style",
|
|
172
|
+
"StyleList",
|
|
118
173
|
"TabProperties",
|
|
119
|
-
"
|
|
174
|
+
"TrackChange",
|
|
175
|
+
"TrackChangeAuthor",
|
|
176
|
+
"TrackChangeAuthorList",
|
|
120
177
|
"TrackChangeConfig",
|
|
178
|
+
"TrackChangeList",
|
|
179
|
+
"TextSpan",
|
|
121
180
|
"XmlSource",
|
|
122
181
|
"element_to_model",
|
|
123
182
|
"load_schema",
|
|
124
183
|
"parse_begin_num",
|
|
184
|
+
"parse_bullet",
|
|
185
|
+
"parse_bullet_para_head",
|
|
186
|
+
"parse_bullets",
|
|
125
187
|
"parse_doc_option",
|
|
126
188
|
"parse_generic_element",
|
|
127
189
|
"parse_header_element",
|
|
128
190
|
"parse_memo_properties",
|
|
129
191
|
"parse_memo_shape",
|
|
192
|
+
"parse_paragraph_alignment",
|
|
193
|
+
"parse_paragraph_auto_spacing",
|
|
194
|
+
"parse_paragraph_border",
|
|
195
|
+
"parse_paragraph_break_setting",
|
|
196
|
+
"parse_paragraph_line_spacing",
|
|
197
|
+
"parse_paragraph_margin",
|
|
198
|
+
"parse_paragraph_property",
|
|
199
|
+
"parse_paragraph_properties",
|
|
130
200
|
"parse_header_xml",
|
|
131
201
|
"parse_paragraph_element",
|
|
132
202
|
"parse_ref_list",
|
|
133
203
|
"parse_run_element",
|
|
204
|
+
"parse_style",
|
|
205
|
+
"parse_styles",
|
|
206
|
+
"parse_track_change",
|
|
207
|
+
"parse_track_change_author",
|
|
208
|
+
"parse_track_change_authors",
|
|
209
|
+
"parse_track_changes",
|
|
134
210
|
"parse_section_element",
|
|
135
211
|
"parse_section_xml",
|
|
136
212
|
"parse_text_span",
|