Python 文档转换器 — 简单、稳定、快速的服务端文档格式转换
Project description
pydoctrans
把 LibreOffice 驯服成可靠的服务端文档转换引擎。
pip install pydoctrans,三行代码把 Word/Excel/PPT 转成 PDF。不会卡死、不会僵尸进程、不会一个文件拖垮整个服务。
如果你在服务端用过 LibreOffice,这些场景你大概率见过
# 同时来两个请求,第二个悄悄丢了——LO 单实例锁,根本不能并行
# 文件大一点就卡住,没超时,没响应,整个队列堵死
# 和 CUDA / 其他系统库冲突,莫名其妙 Signal 11 崩溃
# 僵尸进程堆了几十个,没人回收
# 并发一多直接 OOM,一个 soffice.bin 吃 1G 内存
pydoctrans 怎么解决的
| 你的痛点 | pydoctrans 的做法 |
|---|---|
| 不能并行 | HOME 目录隔离:每次转换独立 ~/.config/libreoffice,管道名不同,真正并行跑 |
| 卡死没响应 | 请求级超时:subprocess.run(timeout) → SIGTERM → SIGKILL → waitpid,不留僵尸 |
| 库冲突崩溃 | LD_LIBRARY_PATH 锁定:LO 只加载自己 program/ 下的 .so,不碰 CUDA 或系统库 |
| OOM | Semaphore 槽位控制:LO_MAX_CONCURRENT 限制同时在跑的 LO 进程数 |
| 一个坏文件堵全部 | 独立进程 + 超时兜底:坏文件超时被杀,不影响其他请求 |
| 关闭丢任务 | 优雅关闭:SIGTERM → 拒新请求 → 等在途完成 → 清理沙箱 |
可靠性的底线
- 中文字体开箱即用:Docker 镜像预装 Noto CJK,不再满屏豆腐块
- 文件类型自动检测:URL 下载的文件没扩展名?读魔术字节,PDF/DOCX/ODT 自己认
- 指数退避重试:URL 下载失败 1s → 2s → 4s 自动重试
- 孤儿沙箱自动清理:进程崩溃残留的临时目录,启动时扫描清理
快速开始
pip install pydoctrans
from pydoctrans import convert
with open("report.docx", "rb") as f:
pdf = convert(f.read(), to="pdf", file_name="report.docx")
with open("report.pdf", "wb") as f:
f.write(pdf)
特性
- 真正并行:每个转换独立 HOME 目录,不受 LO 单实例限制
- 超时兜底:请求级超时,超时即杀,不留僵尸进程
- 库冲突隔离:LD_LIBRARY_PATH 锁定 LO 自身目录,不与 CUDA 等组件冲突
- 并发槽位:Semaphore 控制 LO 进程上限,防止 OOM
- 中文字体:Docker 镜像预装 Noto CJK,中文文档不出乱码
- 文件类型检测:魔术字节自动识别,无扩展名的文件也能正确转换
- 回调钩子:转换前/后注入自定义逻辑(校验、水印、上传 S3)
- HTTP API:独立微服务部署,Docker 开箱即用
- Prometheus 指标:请求数、耗时、槽位利用率实时可观测
- 优雅关闭:SIGTERM 下等在途任务完成,不丢请求
纯 Python,怎么用都行
纯 Python 实现,pip install 即用。内核模块边界清晰——沙箱、并发、引擎各司其职,换引擎不碰业务代码。底层对接 LibreOffice 26.2.4,沉淀二十年的格式兼容能力——Word/Excel/PPT 新旧版本、复杂排版、嵌入对象都能正确转换,不挑文件不丢格式。
pydoctrans/
├── engine/ ← 转换引擎抽象(加新引擎只需实现 Engine 基类)
├── sandbox.py ← HOME 隔离,独立模块,可单独拿出来用
├── pool.py ← 并发控制,Semaphore 封装,不绑死 LO
├── env.py ← 环境检测,支持 Linux/macOS/手动安装/Snap/Flatpak
├── filetype.py ← 魔术字节检测,独立可复用
├── hooks.py ← 回调钩子系统,Protocol 协议,不侵入引擎
├── convert.py ← 公共 API,三行代码接入
├── server.py ← FastAPI 服务,可独立部署
└── __main__.py ← CLI 入口
五种调用方式,同一套内核
# ① 代码调用 — 嵌入你的 Python 项目
from pydoctrans import convert
pdf = convert(docx_bytes, to="pdf", file_name="report.docx")
# ② 命令行 — 运维脚本、CI/CD
python -m pydoctrans convert report.docx -t pdf
# ③ HTTP 服务 — 跨语言调用(Java/Go/Node 都能用)
python -m pydoctrans serve --port 8000
curl -F "file=@report.docx" -F "to=pdf" http://localhost:8000/api/v1/convert
# 也可以直接给 URL,自动下载后转换
curl -F "url=https://example.com/report.docx" -F "to=pdf" \
http://localhost:8000/api/v1/convert/url -o report.pdf
# ④ Docker — 一条命令拉起
docker run -p 8000:8000 pydoctrans
# ⑤ Docker Compose — 生产部署
docker compose up -d
不管你是在 FastAPI 项目里当库使、在 Airflow 里用命令行调、还是微服务架构里独立部署,内核完全一样,没学两套东西。
使用方式
命令行
# 基本转换
python -m pydoctrans convert input.docx output.pdf
# 指定格式(自动生成输出文件名)
python -m pydoctrans convert input.docx -t pdf
# 启动 HTTP 服务
python -m pydoctrans serve --port 8000
Python API
from pydoctrans import convert, ConversionContext
# 基本转换
pdf = convert(docx_bytes, to="pdf", file_name="report.docx")
# 带钩子
def log_size(ctx: ConversionContext) -> None:
print(f"输出: {len(ctx.data)} 字节")
pdf = convert(docx, to="pdf", file_name="r.docx", after=[log_size])
HTTP API
POST /api/v1/convert — 上传文件 → 转换 → 返回文件
POST /api/v1/convert/url — 从 URL 下载 → 转换
GET /api/v1/health — 健康检查
GET /api/v1/engines — 可用引擎列表
GET /metrics — Prometheus 指标
curl -F "file=@report.docx" -F "to=pdf" http://localhost:8000/api/v1/convert -o report.pdf
Docker
docker build -t pydoctrans .
docker run -p 8000:8000 -e LO_MAX_CONCURRENT=4 -e GRACE_PERIOD=30 pydoctrans
配置
所有配置通过环境变量控制:
| 变量 | 默认值 | 说明 |
|---|---|---|
LO_MAX_CONCURRENT |
10 |
最大并发转换数 |
LO_TIMEOUT |
300 |
LO 转换超时(秒) |
MAX_FILE_SIZE_MB |
50 |
上传文件大小限制(MB) |
GRACE_PERIOD |
0 |
优雅关闭最长等待(秒),0=不等待,超时强制终止 |
TMP_DIR |
/tmp |
沙箱父目录 |
回调钩子
from pydoctrans import ConversionContext, convert
def validate_size(ctx: ConversionContext) -> None:
"""转换前校验文件大小。"""
if len(ctx.data) > 10 * 1024 * 1024:
raise ValueError("文件超过 10MB")
def upload_to_s3(ctx: ConversionContext) -> None:
"""转换后上传到 S3。"""
ctx.meta["s3_url"] = s3_client.put(ctx.data)
pdf = convert(
docx_bytes, to="pdf", file_name="report.docx",
before=[validate_size],
after=[upload_to_s3],
)
路线图
- LibreOffice 引擎 — Sandbox 隔离 + 并发控制 + HTTP API
- 回调钩子 — 转换前/后注入自定义逻辑
- Prometheus 指标 + 优雅关闭
- Pandoc 引擎 — 纯文本格式转换(Markdown、LaTeX、reST 等),高语义保真
- WeasyPrint 引擎 — HTML/CSS → PDF,适合报表、发票等排版场景
许可
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydoctrans-1.0.1.tar.gz.
File metadata
- Download URL: pydoctrans-1.0.1.tar.gz
- Upload date:
- Size: 30.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb6eba2d1279578bf4b88a5eaf5327ce72857d245c22856f04738d63c960cd5b
|
|
| MD5 |
d22bca0a2d1b56388e65db7e21627f38
|
|
| BLAKE2b-256 |
716d33907fda160b506a94872fdd1f8f30c8bf891c37f010589f6a05f907a9be
|
File details
Details for the file pydoctrans-1.0.1-py3-none-any.whl.
File metadata
- Download URL: pydoctrans-1.0.1-py3-none-any.whl
- Upload date:
- Size: 27.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba001d0ffd354c490900809fb638ac6ff0b67b566dcaab24df0e84ceafed5274
|
|
| MD5 |
258b2c96295afbc32d5b872cc81d5b09
|
|
| BLAKE2b-256 |
7b799e513dc2e143d345384e4e1f096be07a8a7a2e20a60d4f23b4585da28f8d
|