mddocx 0.4.3__py3-none-any.whl
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.
- mddocx/__init__.py +9 -0
- mddocx/cli.py +228 -0
- mddocx/converter/__init__.py +43 -0
- mddocx/converter/base.py +442 -0
- mddocx/converter/elements/__init__.py +31 -0
- mddocx/converter/elements/base.py +39 -0
- mddocx/converter/elements/blockquote.py +115 -0
- mddocx/converter/elements/code.py +69 -0
- mddocx/converter/elements/heading.py +57 -0
- mddocx/converter/elements/hr.py +67 -0
- mddocx/converter/elements/html.py +471 -0
- mddocx/converter/elements/image.py +254 -0
- mddocx/converter/elements/links.py +253 -0
- mddocx/converter/elements/list.py +370 -0
- mddocx/converter/elements/table.py +442 -0
- mddocx/converter/elements/task_list.py +140 -0
- mddocx/converter/elements/text.py +488 -0
- mddocx/webui/README.md +141 -0
- mddocx/webui/__init__.py +6 -0
- mddocx/webui/app.py +342 -0
- mddocx/webui/config.py +66 -0
- mddocx/webui/start_webui.py +29 -0
- mddocx/webui/static/css/styles.css +1011 -0
- mddocx/webui/static/js/app.js +609 -0
- mddocx/webui/templates/base.html +59 -0
- mddocx/webui/templates/index.html +167 -0
- mddocx/webui/templates/preview.html +148 -0
- mddocx/webui/tests/__init__.py +1 -0
- mddocx/webui/tests/test_basic.py +213 -0
- mddocx-0.4.3.dist-info/METADATA +377 -0
- mddocx-0.4.3.dist-info/RECORD +35 -0
- mddocx-0.4.3.dist-info/WHEEL +5 -0
- mddocx-0.4.3.dist-info/entry_points.txt +3 -0
- mddocx-0.4.3.dist-info/licenses/LICENSE +21 -0
- mddocx-0.4.3.dist-info/top_level.txt +1 -0
mddocx/__init__.py
ADDED
mddocx/cli.py
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令行工具
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
from .converter import BaseConverter
|
|
12
|
+
from .converter.base import MD2DocxError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def convert_file(input_file: str, output_file: str, debug: bool = False) -> None:
|
|
16
|
+
"""转换文件
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
input_file: 输入的 Markdown 文件路径
|
|
20
|
+
output_file: 输出的 DOCX 文件路径
|
|
21
|
+
debug: 是否显示调试信息
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
FileNotFoundError: 输入文件不存在
|
|
25
|
+
PermissionError: 文件权限错误
|
|
26
|
+
MD2DocxError: 转换过程中的错误
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
# 检查输入文件是否存在
|
|
30
|
+
input_path = Path(input_file)
|
|
31
|
+
if not input_path.exists():
|
|
32
|
+
raise FileNotFoundError(f"输入文件不存在: {input_file}")
|
|
33
|
+
|
|
34
|
+
if not input_path.is_file():
|
|
35
|
+
raise ValueError(f"输入路径不是文件: {input_file}")
|
|
36
|
+
|
|
37
|
+
# 读取输入文件
|
|
38
|
+
with open(input_file, "r", encoding="utf-8") as f:
|
|
39
|
+
content = f.read()
|
|
40
|
+
|
|
41
|
+
except (OSError, IOError) as e:
|
|
42
|
+
raise FileNotFoundError(f"无法读取输入文件 {input_file}: {e}")
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
# 初始化转换器并执行转换
|
|
46
|
+
converter = BaseConverter(debug=debug)
|
|
47
|
+
doc = converter.convert(content)
|
|
48
|
+
|
|
49
|
+
except MD2DocxError:
|
|
50
|
+
# 转换器自定义错误,直接重新抛出
|
|
51
|
+
raise
|
|
52
|
+
|
|
53
|
+
# 检查输出文件是否被占用,如果是则添加时间戳后缀
|
|
54
|
+
output_path = Path(output_file)
|
|
55
|
+
final_output_file = output_file
|
|
56
|
+
attempt = 0
|
|
57
|
+
|
|
58
|
+
while attempt < 5: # 最多尝试5次
|
|
59
|
+
try:
|
|
60
|
+
# 尝试保存文件
|
|
61
|
+
doc.save(final_output_file)
|
|
62
|
+
print(f"转换完成: {final_output_file}")
|
|
63
|
+
return
|
|
64
|
+
except PermissionError:
|
|
65
|
+
# 文件被占用,添加时间戳后缀
|
|
66
|
+
timestamp = int(time.time())
|
|
67
|
+
new_filename = f"{output_path.stem}_{timestamp}{output_path.suffix}"
|
|
68
|
+
final_output_file = str(output_path.parent / new_filename)
|
|
69
|
+
print(f"文件 {output_file} 被占用,尝试保存为: {final_output_file}")
|
|
70
|
+
attempt += 1
|
|
71
|
+
except Exception as e:
|
|
72
|
+
# 其他错误,直接抛出
|
|
73
|
+
raise e
|
|
74
|
+
|
|
75
|
+
# 如果多次尝试后仍然失败
|
|
76
|
+
raise PermissionError(
|
|
77
|
+
f"无法保存文件,请关闭可能正在使用该文件的应用程序: {output_file}"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_help_texts(lang: str = "zh") -> dict:
|
|
82
|
+
"""获取指定语言的帮助文本"""
|
|
83
|
+
|
|
84
|
+
texts = {
|
|
85
|
+
"zh": {
|
|
86
|
+
"description": """\
|
|
87
|
+
Markdown to DOCX 转换工具 v{0}
|
|
88
|
+
|
|
89
|
+
一个功能强大的 Markdown 转 DOCX 文档转换工具,支持丰富的 Markdown 语法。
|
|
90
|
+
|
|
91
|
+
支持的功能:
|
|
92
|
+
• 标准 Markdown 语法 (标题、列表、链接、图片等)
|
|
93
|
+
• 表格转换和对齐
|
|
94
|
+
• 代码块和语法高亮
|
|
95
|
+
• 任务列表 (TODO)
|
|
96
|
+
• 引用块 (支持嵌套)
|
|
97
|
+
• HTML 标签支持
|
|
98
|
+
|
|
99
|
+
项目主页: https://github.com/wangqiqi/md2docx
|
|
100
|
+
文档: https://github.com/wangqiqi/md2docx#readme
|
|
101
|
+
问题反馈: https://github.com/wangqiqi/md2docx/issues
|
|
102
|
+
|
|
103
|
+
使用示例:
|
|
104
|
+
mddocx README.md output.docx
|
|
105
|
+
mddocx --debug document.md report.docx
|
|
106
|
+
""".format(
|
|
107
|
+
__version__
|
|
108
|
+
),
|
|
109
|
+
"input_help": "输入的 Markdown 文件路径",
|
|
110
|
+
"output_help": "输出的 DOCX 文件路径",
|
|
111
|
+
"debug_help": "显示调试信息和详细的转换过程",
|
|
112
|
+
"version_help": "显示版本信息 (-v, -V)",
|
|
113
|
+
"lang_help": "选择帮助信息的语言 (zh/en, 默认: zh)",
|
|
114
|
+
},
|
|
115
|
+
"en": {
|
|
116
|
+
"description": """\
|
|
117
|
+
Markdown to DOCX Converter v{0}
|
|
118
|
+
|
|
119
|
+
A powerful Markdown to DOCX document conversion tool that supports rich Markdown syntax.
|
|
120
|
+
|
|
121
|
+
Supported features:
|
|
122
|
+
• Standard Markdown syntax (headings, lists, links, images, etc.)
|
|
123
|
+
• Table conversion and alignment
|
|
124
|
+
• Code blocks with syntax highlighting
|
|
125
|
+
• Task lists (TODO)
|
|
126
|
+
• Blockquotes (nested support)
|
|
127
|
+
• HTML tag support
|
|
128
|
+
|
|
129
|
+
Homepage: https://github.com/wangqiqi/md2docx
|
|
130
|
+
Documentation: https://github.com/wangqiqi/md2docx#readme
|
|
131
|
+
Bug reports: https://github.com/wangqiqi/md2docx/issues
|
|
132
|
+
|
|
133
|
+
Usage examples:
|
|
134
|
+
mddocx README.md output.docx
|
|
135
|
+
mddocx --debug document.md report.docx
|
|
136
|
+
""".format(
|
|
137
|
+
__version__
|
|
138
|
+
),
|
|
139
|
+
"input_help": "Path to input Markdown file",
|
|
140
|
+
"output_help": "Path to output DOCX file",
|
|
141
|
+
"debug_help": "Show debug information and detailed conversion process",
|
|
142
|
+
"version_help": "Show version information (-v, -V)",
|
|
143
|
+
"lang_help": "Choose language for help information (zh/en, default: zh)",
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return texts.get(lang, texts["zh"])
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def main() -> None:
|
|
151
|
+
"""主函数"""
|
|
152
|
+
|
|
153
|
+
# 创建主解析器(先用英文创建,然后根据参数重新设置)
|
|
154
|
+
parser = argparse.ArgumentParser(
|
|
155
|
+
prog="mddocx",
|
|
156
|
+
description="Markdown to DOCX Converter",
|
|
157
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
158
|
+
add_help=False, # 暂时禁用自动帮助
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 添加语言参数(需要在其他参数之前)
|
|
162
|
+
parser.add_argument(
|
|
163
|
+
"--lang",
|
|
164
|
+
choices=["zh", "en"],
|
|
165
|
+
default="zh",
|
|
166
|
+
help="Choose language for help information (zh/en, default: zh)",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# 解析语言参数
|
|
170
|
+
args, remaining = parser.parse_known_args()
|
|
171
|
+
|
|
172
|
+
# 获取对应语言的文本
|
|
173
|
+
texts = get_help_texts(args.lang)
|
|
174
|
+
|
|
175
|
+
# 重新创建解析器,使用正确的语言
|
|
176
|
+
parser = argparse.ArgumentParser(
|
|
177
|
+
prog="mddocx",
|
|
178
|
+
description=texts["description"],
|
|
179
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# 重新添加语言参数
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"--lang",
|
|
185
|
+
choices=["zh", "en"],
|
|
186
|
+
default="zh",
|
|
187
|
+
help=texts["lang_help"],
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# 添加位置参数
|
|
191
|
+
parser.add_argument("input", help=texts["input_help"])
|
|
192
|
+
parser.add_argument("output", help=texts["output_help"])
|
|
193
|
+
|
|
194
|
+
# 添加可选参数
|
|
195
|
+
parser.add_argument(
|
|
196
|
+
"--debug",
|
|
197
|
+
action="store_true",
|
|
198
|
+
help=texts["debug_help"],
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# 添加版本信息
|
|
202
|
+
parser.add_argument(
|
|
203
|
+
"--version",
|
|
204
|
+
"-v",
|
|
205
|
+
"-V",
|
|
206
|
+
action="version",
|
|
207
|
+
version="mddocx v{0}".format(__version__),
|
|
208
|
+
help=texts["version_help"],
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# 重新解析所有参数
|
|
212
|
+
args = parser.parse_args(remaining)
|
|
213
|
+
|
|
214
|
+
args = parser.parse_args()
|
|
215
|
+
|
|
216
|
+
if not Path(args.input).exists():
|
|
217
|
+
print(f"错误: 输入文件不存在: {args.input}")
|
|
218
|
+
sys.exit(1)
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
convert_file(args.input, args.output, args.debug)
|
|
222
|
+
except Exception as e:
|
|
223
|
+
print(f"错误: {str(e)}")
|
|
224
|
+
sys.exit(1)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
if __name__ == "__main__":
|
|
228
|
+
main()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
转换器包
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .base import (
|
|
6
|
+
BaseConverter,
|
|
7
|
+
ConvertError,
|
|
8
|
+
ElementConverter,
|
|
9
|
+
MD2DocxError,
|
|
10
|
+
ParseError,
|
|
11
|
+
)
|
|
12
|
+
from .elements import (
|
|
13
|
+
BlockquoteConverter,
|
|
14
|
+
CodeConverter,
|
|
15
|
+
HeadingConverter,
|
|
16
|
+
HRConverter,
|
|
17
|
+
HtmlConverter,
|
|
18
|
+
ImageConverter,
|
|
19
|
+
LinkConverter,
|
|
20
|
+
ListConverter,
|
|
21
|
+
TableConverter,
|
|
22
|
+
TaskListConverter,
|
|
23
|
+
TextConverter,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"BaseConverter",
|
|
28
|
+
"ElementConverter",
|
|
29
|
+
"MD2DocxError",
|
|
30
|
+
"ParseError",
|
|
31
|
+
"ConvertError",
|
|
32
|
+
"HeadingConverter",
|
|
33
|
+
"TextConverter",
|
|
34
|
+
"BlockquoteConverter",
|
|
35
|
+
"ListConverter",
|
|
36
|
+
"CodeConverter",
|
|
37
|
+
"LinkConverter",
|
|
38
|
+
"ImageConverter",
|
|
39
|
+
"TableConverter",
|
|
40
|
+
"HRConverter",
|
|
41
|
+
"TaskListConverter",
|
|
42
|
+
"HtmlConverter",
|
|
43
|
+
]
|