qparse 0.1.0__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.
Files changed (41) hide show
  1. qparse-0.1.0/LICENSE +21 -0
  2. qparse-0.1.0/MANIFEST.in +6 -0
  3. qparse-0.1.0/PKG-INFO +454 -0
  4. qparse-0.1.0/README.md +420 -0
  5. qparse-0.1.0/pyproject.toml +62 -0
  6. qparse-0.1.0/qmd_cli.py +262 -0
  7. qparse-0.1.0/qparse/__init__.py +16 -0
  8. qparse-0.1.0/qparse/docx_render/__init__.py +3 -0
  9. qparse-0.1.0/qparse/docx_render/docx_render.py +68 -0
  10. qparse-0.1.0/qparse/docx_render/write_buffer.py +412 -0
  11. qparse-0.1.0/qparse/markdwon_document/__init__.py +28 -0
  12. qparse-0.1.0/qparse/markdwon_document/analysis_document.py +40 -0
  13. qparse-0.1.0/qparse/markdwon_document/base_document.py +87 -0
  14. qparse-0.1.0/qparse/markdwon_document/markdwon_document.py +16 -0
  15. qparse-0.1.0/qparse/markdwon_document/nodes/__init__.py +5 -0
  16. qparse-0.1.0/qparse/markdwon_document/nodes/answer_node.py +97 -0
  17. qparse-0.1.0/qparse/markdwon_document/nodes/base_node.py +51 -0
  18. qparse-0.1.0/qparse/markdwon_document/nodes/img_node.py +31 -0
  19. qparse-0.1.0/qparse/markdwon_document/nodes/text_node.py +139 -0
  20. qparse-0.1.0/qparse/markdwon_document/question_document.py +17 -0
  21. qparse-0.1.0/qparse/markdwon_document/stem_document.py +64 -0
  22. qparse-0.1.0/qparse/markdwon_document/table_document.py +126 -0
  23. qparse-0.1.0/qparse/markdwon_loader.py +189 -0
  24. qparse-0.1.0/qparse/markdwon_render.py +123 -0
  25. qparse-0.1.0/qparse/qmd_packer.py +475 -0
  26. qparse-0.1.0/qparse/qmd_unpacker.py +169 -0
  27. qparse-0.1.0/qparse/render_option/__init__.py +40 -0
  28. qparse-0.1.0/qparse/render_option/default_render_option.py +86 -0
  29. qparse-0.1.0/qparse/render_option/default_render_template.md +21 -0
  30. qparse-0.1.0/qparse/render_option/referance.docx +0 -0
  31. qparse-0.1.0/qparse/render_option/theme.json +245 -0
  32. qparse-0.1.0/qparse/utils/__init__.py +3 -0
  33. qparse-0.1.0/qparse/utils/html_full_protector.py +154 -0
  34. qparse-0.1.0/qparse.egg-info/PKG-INFO +454 -0
  35. qparse-0.1.0/qparse.egg-info/SOURCES.txt +39 -0
  36. qparse-0.1.0/qparse.egg-info/dependency_links.txt +1 -0
  37. qparse-0.1.0/qparse.egg-info/entry_points.txt +2 -0
  38. qparse-0.1.0/qparse.egg-info/requires.txt +6 -0
  39. qparse-0.1.0/qparse.egg-info/top_level.txt +2 -0
  40. qparse-0.1.0/requirements.txt +20 -0
  41. qparse-0.1.0/setup.cfg +4 -0
qparse-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hanbuhuai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
4
+ recursive-include qparse/render_option *.json *.md *.docx
5
+ global-exclude __pycache__ *.py[cod]
6
+ prune qparse/docx_render/bak
qparse-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,454 @@
1
+ Metadata-Version: 2.4
2
+ Name: qparse
3
+ Version: 0.1.0
4
+ Summary: Structured Markdown lesson plans to DOCX, with .qmd pack/unpack tooling.
5
+ Author: hanbuhuai
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/hanbuhuai/qparse
8
+ Project-URL: Repository, https://github.com/hanbuhuai/qparse
9
+ Project-URL: Issues, https://github.com/hanbuhuai/qparse/issues
10
+ Keywords: markdown,docx,pandoc,lesson-plan,qmd
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Text Processing :: Markup
23
+ Classifier: Topic :: Education
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: beautifulsoup4>=4.12
28
+ Requires-Dist: python-docx>=1.1
29
+ Requires-Dist: docxcompose>=1.4
30
+ Requires-Dist: Jinja2>=3.1
31
+ Requires-Dist: pypandoc>=1.13
32
+ Requires-Dist: typer>=0.12
33
+ Dynamic: license-file
34
+
35
+ # QParse
36
+
37
+ 将结构化 Markdown 教案渲染为 Word(DOCX),并支持 `.qmd` 单文件打包分发。
38
+
39
+ 典型场景:数学备课 / 习题讲义。支持:
40
+
41
+ - `@import` 分题导入
42
+ - `$...$` LaTeX 公式
43
+ - 填空 / 选择 / 多选 / 简答
44
+ - 自动生成参考答案
45
+ - Markdown 表格与 HTML 表格
46
+ - 图片、分页、主题模板
47
+ - `.qmd` 打包 / 解包(资源按 SHA-256 去重)
48
+
49
+ ---
50
+
51
+ ## 目录结构
52
+
53
+ ```text
54
+ QParse/
55
+ ├── qparse/ # 核心库
56
+ │ ├── markdwon_loader.py # Markdown 加载、@import、题号装饰
57
+ │ ├── markdwon_render.py # render.md 解析与整篇渲染
58
+ │ ├── markdwon_document/ # 文档节点树(题干/答案/表格/图片)
59
+ │ ├── docx_render/ # Pandoc + python-docx 输出 DOCX
60
+ │ ├── render_option/ # 默认主题、模板、referance.docx
61
+ │ ├── qmd_packer.py # .qmd 打包
62
+ │ ├── qmd_unpacker.py # .qmd 解包
63
+ │ └── utils/ # 空格/换行保护等工具
64
+ ├── qmd_cli.py # Typer 命令行入口
65
+ ├── dev.py # 开发调试脚本
66
+ ├── render.md # 渲染入口配置示例
67
+ ├── QParse.code-workspace # 工作区(代码 + 备课目录)
68
+ ├── qmd-package-design.md # .qmd 设计说明
69
+ └── README.md
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 环境依赖
75
+
76
+ 建议使用项目内虚拟环境:
77
+
78
+ ```powershell
79
+ cd d:\dev\QParse
80
+ .\venv\Scripts\activate
81
+ ```
82
+
83
+ 主要依赖:
84
+
85
+ | 包 | 用途 |
86
+ |----|------|
87
+ | `beautifulsoup4` | HTML/Markdown 中间结构解析 |
88
+ | `pypandoc` + Pandoc | Markdown/HTML → DOCX |
89
+ | `python-docx` | DOCX 后处理(表格、边框、图片) |
90
+ | `docxcompose` | 多段 DOCX 合并 |
91
+ | `jinja2` | 题干/答案模板渲染 |
92
+ | `typer` | 命令行工具 |
93
+
94
+ 系统需已安装 [Pandoc](https://pandoc.org/)。
95
+
96
+ ---
97
+
98
+ ## 快速开始
99
+
100
+ ### 1. 为 main.md 生成 render.md
101
+
102
+ ```powershell
103
+ python qmd_cli.py init "d:\workspace\lesson_plan\...\main.md" -o ".\render.md" -f
104
+ ```
105
+
106
+ 生成示例:
107
+
108
+ ```markdown
109
+ <render src="D:\workspace\...\main.md">
110
+ <file type="docx" dist="习题版.docx">
111
+ <doc theme="Worksheet">
112
+ <after>
113
+ <pagebreak></pagebreak>
114
+ # 参考答案
115
+
116
+ <reference-answer></reference-answer>
117
+
118
+ </after>
119
+ </doc>
120
+ </file>
121
+ </render>
122
+ ```
123
+
124
+ ### 2. 直接渲染 DOCX
125
+
126
+ ```powershell
127
+ python qmd_cli.py render .\render.md
128
+ ```
129
+
130
+ ### 3. 打包为 .qmd 再解包渲染
131
+
132
+ ```powershell
133
+ # 打包
134
+ python qmd_cli.py pack .\render.md -o .\lesson.qmd
135
+
136
+ # 解包(目录保留)
137
+ python qmd_cli.py unpack .\lesson.qmd -t .\lesson_unpacked
138
+
139
+ # 渲染解包后的入口
140
+ python qmd_cli.py render .\lesson_unpacked\render.md
141
+
142
+ # 或一键:打包 → 解包 → 渲染
143
+ python qmd_cli.py build .\render.md -o .\lesson.qmd -u .\lesson_unpacked
144
+ ```
145
+
146
+ ---
147
+
148
+ ## 命令行工具
149
+
150
+ 入口文件:`qmd_cli.py`
151
+
152
+ ```powershell
153
+ python qmd_cli.py --help
154
+ ```
155
+
156
+ | 命令 | 说明 |
157
+ |------|------|
158
+ | `init` | 输入 `main.md`,生成默认 `render.md` |
159
+ | `pack` | 将 `render.md` 及依赖打包为 `.qmd` |
160
+ | `unpack` | 解包 `.qmd` 到工作目录 |
161
+ | `render` | 根据 `render.md` 渲染 DOCX |
162
+ | `build` | 打包 + 解包 + 渲染一键完成 |
163
+
164
+ ### init
165
+
166
+ ```powershell
167
+ python qmd_cli.py init <main.md> [-o render.md] [-d 习题版.docx] [--theme Worksheet] [-f]
168
+ ```
169
+
170
+ - 默认输出到 `main.md` 同级的 `render.md`
171
+ - `-o` 可指定输出路径(例如项目根目录)
172
+ - `-f` 覆盖已存在文件
173
+
174
+ ### pack
175
+
176
+ ```powershell
177
+ python qmd_cli.py pack <render.md> [-o lesson.qmd] [-w QParse.code-workspace]
178
+ ```
179
+
180
+ ### unpack
181
+
182
+ ```powershell
183
+ python qmd_cli.py unpack <lesson.qmd> [-t lesson_unpacked]
184
+ ```
185
+
186
+ ### render
187
+
188
+ ```powershell
189
+ python qmd_cli.py render <render.md>
190
+ ```
191
+
192
+ ### build
193
+
194
+ ```powershell
195
+ python qmd_cli.py build <render.md> [-o lesson.qmd] [-u lesson_unpacked]
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Python API
201
+
202
+ ```python
203
+ from qparse import (
204
+ MarkdownLoader,
205
+ MarkdwonRender,
206
+ QmdPacker,
207
+ QmdUnpacker,
208
+ )
209
+
210
+ # 加载 Markdown(展开 @import,装饰题号)
211
+ loader = MarkdownLoader(r"d:\path\to\main.md")
212
+ soup = loader.get_soup()
213
+ answers = loader.get_reference_answer_markdwon()
214
+
215
+ # 按 render.md 渲染
216
+ render = MarkdwonRender(src=r"d:\dev\QParse\render.md")
217
+ outputs = render.render() # List[Path]
218
+
219
+ # 打包 / 解包
220
+ packer = QmdPacker()
221
+ qmd_path = packer.pack(entry=r"d:\dev\QParse\render.md", output=r"d:\dev\QParse\lesson.qmd")
222
+
223
+ unpacker = QmdUnpacker(str(qmd_path))
224
+ work_dir = unpacker.unpack(target=r"d:\dev\QParse\lesson_unpacked")
225
+ entry = unpacker.entry_path
226
+ ```
227
+
228
+ 开发调试可参考 `dev.py`:
229
+
230
+ ```powershell
231
+ python dev.py
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Markdown 约定
237
+
238
+ ### 分文件导入
239
+
240
+ ```markdown
241
+ @import "./01/main.md"
242
+ @import "./02/main.md"
243
+ ```
244
+
245
+ ### 题目结构(示意)
246
+
247
+ ```html
248
+ <question>
249
+ <stem>
250
+ 在 $\triangle ABC$ 中,……( )。
251
+ </stem>
252
+ <span class="chiose">C</span>
253
+ </question>
254
+ ```
255
+
256
+ 题型 class:
257
+
258
+ | class | 含义 |
259
+ |-------|------|
260
+ | `blank` | 填空 |
261
+ | `chiose` / `choice` | 单选 |
262
+ | `multiple-choice` / `multiple-chiose` | 多选 |
263
+ | `answer` | 简答 |
264
+
265
+ Loader 会自动:
266
+
267
+ 1. 为每个 `<question>` 写入连续 `question_id`
268
+ 2. 标记 `span[type=answer]`
269
+ 3. 写入 `answer_types`
270
+
271
+ ### 参考答案
272
+
273
+ 在 `render.md` 的 `before` / `after` 中使用:
274
+
275
+ ```html
276
+ <reference-answer></reference-answer>
277
+ ```
278
+
279
+ 生成规则:
280
+
281
+ - 填空 / 选择 / 多选:连续客观题合并为 Markdown 表格
282
+ - 简答:`题号、答案`(使用顿号,避免 Pandoc 识别为有序列表)
283
+ - 答案只取文本,不保留原始 `<span>`
284
+
285
+ 示例:
286
+
287
+ ```markdown
288
+ | 1 | 2 |
289
+ | --- | --- |
290
+ | $\sqrt{3}-1$ | C |
291
+
292
+ 3、(Ⅰ)$\frac{8\sqrt{10}}{9}$;(Ⅱ)$\frac{\sqrt{6}}{2}$
293
+ ```
294
+
295
+ ### 公式与换行
296
+
297
+ - 行内公式:`$...$`
298
+ - 源文件中的 `\n` 在加载阶段转为 `<br/>`,DOCX 使用 Pandoc `hard_line_breaks`
299
+ - 普通空格与 Tab 经 `HtmlFullProtector` 保护,避免 BeautifulSoup 丢失
300
+
301
+ ### 图片
302
+
303
+ ```markdown
304
+ ![说明](./assets/img/demo.png)
305
+ ```
306
+
307
+ 打包时图片进入 `resources/<sha256>.ext`,解包后复制到文档同级 `assets/`。
308
+
309
+ ---
310
+
311
+ ## render.md 说明
312
+
313
+ `render.md` 是渲染编排入口,不是正文本身。
314
+
315
+ ```html
316
+ <render src="绝对或相对路径/main.md" theme="可选主题json">
317
+ <file type="docx" dist="习题版.docx">
318
+ <doc theme="Worksheet">
319
+ <before>…</before>
320
+ <after>
321
+ <pagebreak></pagebreak>
322
+ # 参考答案
323
+ <reference-answer></reference-answer>
324
+ </after>
325
+ </doc>
326
+ </file>
327
+ </render>
328
+ ```
329
+
330
+ 要点:
331
+
332
+ - `src`:正文 `main.md`(相对路径相对 `render.md` 所在目录解析)
333
+ - `file@dist`:输出 DOCX 文件名/路径
334
+ - `doc@theme`:主题名(来自默认 theme 或外部 json)
335
+ - `before` / `after`:插入正文前后的内容
336
+ - `<reference-answer>`:自动替换为参考答案 Markdown
337
+
338
+ ---
339
+
340
+ ## DOCX 渲染流程
341
+
342
+ ```text
343
+ render.md
344
+ → MarkdownLoader 加载入口与正文
345
+ → 展开 @import / 图片 / 题号
346
+ → before/after 插入(含参考答案)
347
+ → MarkdwonDocument 生成中间 Markdown/HTML buffer
348
+ → Pandoc 转 DOCX(tex_math_dollars + hard_line_breaks + reference-doc)
349
+ → python-docx 后处理表格样式、图片、合并
350
+ → 复制到 dist
351
+ → 清理本次 .qmd_runtime/<uuid>
352
+ ```
353
+
354
+ 表格相关默认配置(可在 `render_option` 中调整):
355
+
356
+ - 宽度 100%
357
+ - 表头加粗
358
+ - 表头底色
359
+ - 边框颜色
360
+ - 单元格居中
361
+
362
+ 并发渲染时,每个 `DocxRender` 使用独立临时子目录,避免互相删除文件。
363
+
364
+ ---
365
+
366
+ ## .qmd 打包设计(摘要)
367
+
368
+ 详细设计见 [qmd-package-design.md](./qmd-package-design.md)。
369
+
370
+ 包内结构:
371
+
372
+ ```text
373
+ lesson.qmd
374
+ ├── manifest.json
375
+ ├── render.md
376
+ ├── documents/ # 保持目录关系的 Markdown
377
+ ├── resources/ # 二进制资源,按 SHA-256 去重
378
+ ├── themes/
379
+ └── templates/
380
+ ```
381
+
382
+ 规则:
383
+
384
+ 1. 绝对路径资源复制后转为包内相对路径
385
+ 2. 相同内容只存一份(哈希去重)
386
+ 3. 解包时按需把资源放到各 Markdown 同级 `assets/`
387
+ 4. 编辑器可直接预览 `./assets/...`
388
+ 5. 重新打包时重新计算哈希并清理未引用资源
389
+
390
+ ---
391
+
392
+ ## 工作区
393
+
394
+ `QParse.code-workspace` 通常包含:
395
+
396
+ 1. 代码目录:`d:\dev\QParse`
397
+ 2. 备课目录:如 `02-必修2备课`
398
+
399
+ 打包器会读取 workspace folders,将文档放入:
400
+
401
+ ```text
402
+ documents/<index>-<folder-name>/...
403
+ ```
404
+
405
+ 避免多个工作区目录同名冲突。
406
+
407
+ ---
408
+
409
+ ## 常见问题
410
+
411
+ ### 1. 简答题被识别成 Word 有序列表
412
+
413
+ 参考答案使用 `3、` 而不是 `3.`。
414
+
415
+ ### 2. 解包后找不到 main.md
416
+
417
+ `MarkdwonRender` 会把 `render.md` 中的相对 `src` 解析为相对 `render.md` 所在目录。请用解包后的 `render.md` 作为渲染入口。
418
+
419
+ ### 3. 两个进程同时渲染报临时文件不存在
420
+
421
+ 临时目录已改为 `.qmd_runtime/<uuid>/`,每个渲染实例独立。
422
+
423
+ ### 4. 表格公式丢失
424
+
425
+ Markdown 分支使用:
426
+
427
+ ```text
428
+ markdown+tex_math_dollars+hard_line_breaks
429
+ ```
430
+
431
+ HTML 表格分支使用:
432
+
433
+ ```text
434
+ html+tex_math_dollars
435
+ ```
436
+
437
+ ### 5. 图片在打包后预览失败
438
+
439
+ 确认解包步骤已执行;图片应出现在对应 Markdown 同级 `assets/` 下。
440
+
441
+ ---
442
+
443
+ ## 开发提示
444
+
445
+ - 项目内历史拼写 `markdwon` 为既有命名,调用时请保持一致,不要只改函数名不改调用方
446
+ - 调试加载结果可写 `soup.html` / `pv.md`(见 `dev.py`)
447
+ - 修改主题与题干模板:`qparse/render_option/`
448
+ - 修改 DOCX 后处理:`qparse/docx_render/write_buffer.py`
449
+
450
+ ---
451
+
452
+ ## 许可证
453
+
454
+ 内部备课工具,按团队约定使用。